我正在构建权限UI,我有一个权限列表,每个权限旁边都有一个选择列表。权限由可观察的对象数组表示,这些对象绑定到选择列表:
<div data-bind="foreach: permissions">
<div class="permission_row">
<span data-bind="text: name"></span>
<select data-bind="value: level, event:{ change: $parent.permissionChanged}">
<option value="0"></option>
<option value="1">R</option>
<option value="2">RW</option>
</select>
</div>
</div>
现在的问题是:当UI刚刚第一次填充时,会引发更改事件。我调用我的ajax函数,获取权限列表,然后为每个权限项引发事件。这真的不是我想要的行为。我希望只有当用户真正为选择列表中的权限选择一个新值时才会提出,我该怎么做?
答案 0 :(得分:88)
实际上你想知道事件是由用户还是程序触发,而且很明显该事件会在初始化时触发。
添加subscription
的淘汰方法在所有情况下都无济于事,为什么因为大部分模型都会像这样实施
(actual KO initilization)
(logical init like load JSON , get data etc)
我们要捕获的实际步骤是3中的更改,但在第二步subscription
将会调用,
所以更好的方法是添加像
<select data-bind="value: level, event:{ change: $parent.permissionChanged}">
并在permissionChanged
函数
this.permissionChanged = function (obj, event) {
if (event.originalEvent) { //user changed
} else { // program changed
}
}
答案 1 :(得分:32)
这只是猜测,但我认为这是因为level
是一个数字。在这种情况下,value
绑定将触发change
事件以使用字符串值更新level
。因此,您可以通过确保level
是一个字符串开始来解决此问题。
此外,更多“敲除”方法是不使用事件处理程序,而是使用observable和subscriptions。将level
设为可观察对象,然后为其添加订阅,只要level
发生更改,该订阅就会运行。
答案 2 :(得分:4)
这是一个可以帮助解决这种奇怪行为的解决方案。我没有找到比手动触发更改事件的按钮更好的解决方案。
编辑:也许这样的自定义绑定可能有所帮助:
ko.bindingHandlers.changeSelectValue = {
init: function(element,valueAccessor){
$(element).change(function(){
var value = $(element).val();
if($(element).is(":focus")){
//Do whatever you want with the new value
}
});
}
};
在您的select data-bind属性中添加:
changeSelectValue: yourSelectValue
答案 3 :(得分:3)
我使用这个自定义绑定(基于RP Niemeyer的this小提琴,请参阅他对this问题的回答),这确保数值正确地从字符串转换为数字(如建议的那样) Michael Best的解决方案:
使用Javascript:
ko.bindingHandlers.valueAsNumber = {
init: function (element, valueAccessor, allBindingsAccessor) {
var observable = valueAccessor(),
interceptor = ko.computed({
read: function () {
var val = ko.utils.unwrapObservable(observable);
return (observable() ? observable().toString() : observable());
},
write: function (newValue) {
observable(newValue ? parseInt(newValue, 10) : newValue);
},
owner: this
});
ko.applyBindingsToNode(element, { value: interceptor });
}
};
示例HTML:
<select data-bind="valueAsNumber: level, event:{ change: $parent.permissionChanged }">
<option value="0"></option>
<option value="1">R</option>
<option value="2">RW</option>
</select>
答案 4 :(得分:2)
如果使用observable而不是原始值,则select不会在初始绑定时引发更改事件。您可以继续绑定到change事件,而不是直接订阅observable。
答案 5 :(得分:1)
快速而肮脏,使用简单的旗帜:
var bindingsApplied = false;
var ViewModel = function() {
// ...
this.permissionChanged = function() {
// ignore, if flag not set
if (!flag) return;
// ...
};
};
ko.applyBindings(new ViewModel());
bindingsApplied = true; // done with the initial population, set flag to true
如果这不起作用,请尝试将最后一行包装在setTimeout()中 - 事件是异步的,因此当applyBindings()已经返回时,最后一行可能仍处于未决状态。
答案 6 :(得分:0)
我遇到了类似的问题,我只修改了事件处理程序以检查变量的类型。该类型仅在用户选择值后设置,而不是在首次加载页面时设置。
self.permissionChanged = function (l) {
if (typeof l != 'undefined') {
...
}
}
这似乎对我有用。
答案 7 :(得分:0)
使用此:
this.permissionChanged = function (obj, event) {
if (event.type != "load") {
}
}
答案 8 :(得分:0)
尝试这个:
self.GetHierarchyNodeList = function (data, index, event)
{
debugger;
if (event.type != "change") {
return;
}
}
event.type == "change"
event.type == "load"
答案 9 :(得分:0)
创建js组件
define([
'Magento_Ui/js/form/element/select',
'mage/translate'
], function (AbstractField, $t) {
'use strict';
return AbstractField.extend({
defaults: {
imports: {
update: 'checkout.steps.shipping-step.shippingAddress.shipping-address-fieldset.country_id:value'
},
modules: {
vat_id: '${ $.parentName }.vat_id'
}
},
/**
* Initializes UISelect component.
*
* @returns {UISelect} Chainable.
*/
initialize: function () {
this._super();
this.vat_id().visible(false);
return this;
},
update: function (value) {
if(value == 'GB'){
this.vat_id().visible(true);
}else{
this.vat_id().visible(false);
}
}
});
});
答案 10 :(得分:-1)
如果您正在使用Knockout,请使用可观察功能敲除的关键功能
使用<TextBlock Text="{Binding SelectedItem.Value, ElementName=ModelList}" />
方法并在该函数中执行并触发ajax调用。