我有这个HTML
<select data-bind="value: $data.id">
<optgroup label="Regions" data-bind="foreach: countries.regions.names">
<option data-bind="html: $data.name, value: $data.value"></option>
</optgroup>
<optgroup label="Countries" data-bind="foreach: shipping.allCountries">
<option data-bind="html: $data.name, value: $data.code"></option>
</optgroup>
</select>
有了这个javascript,它在两个optgroups
中的任何一个中都预先填充了一个ID。ID始终存在!
this.id = ko.observable(data.id);
但是在KnockOut构建select
之后,this.id()
的值为空,并且将返回undefined
。当我订阅该字段时,它会通知我它正在更新,但没有任何内容。
我当前的(脏)修复:
setTimeout(function(){
self.id(data.id);
}, 500);
这是有效的,但当然不推荐。
此外,在select
中选择另一个元素并返回到原始值后,也可以。
如何解决此问题?
注意:选择了正确的元素
失败的原因是<select>
元素的value
在使用foreach
绑定其内容之前被绑定,并且如果模型值本身无法选择,value
绑定将把模型值重置为元素中当前选择的值。
问题示例:http://jsfiddle.net/mbest/8r6KY/
对此有两种解决方案。
1.防止模型值重置
一种解决方案是使用Knockout 3.1(目前处于Beta版)中提供的新绑定选项valueAllowUnset
来防止value
绑定重置模型值。
<select data-bind="value: $data.id, valueAllowUnset: true">
示例:http://jsfiddle.net/mbest/D6dR2/
2.先绑定内容后绑定值
第二种解决方案是在绑定value
之前将<option>
元素放置到位。这可以通过对元素进行自定义绑定来完成,该元素可以早期绑定内容。
<select data-bind="bindInner, value: $data.id">
绑定:
ko.bindingHandlers.bindInner = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
ko.applyBindingsToDescendants(bindingContext, element);
return { controlsDescendantBindings: true };
}
};
示例:http://jsfiddle.net/mbest/ETFsa/
建议
第一个选项使用内置解决方案,但有一个缺点,即UI选择使用setTimeout
(在value
绑定内)。因此,在视图初始化时,您可以在选择中进行可见的更改。我认为,第二种选择是更好的,尽管你当然可以同时使用这两种方法来双重解决问题。
确保您的countries.regions.names实际指向正确的位置。如果这些选项不存在,那么这些值就不存在。