我有一个select
元素,使用options
绑定绑定到复杂javascript对象列表:
<select data-bind="options: availableCountries, optionsText: 'countryName', value: selectedCountry, optionsCaption: 'Choose...'"></select>
其中availableCountries是一个可观察的javascript对象数组。您可以看到完整示例in this fiddle。
现在,当我在列表中选择一个项目时,这可以正常工作。但是,如果我需要更新应用程序的其他部分的值,我将只能使用与availableCountries数组中完全相同的Country对象。这也已在related question中确立,但不幸的是它并没有解决我的问题。
在options binding的文档中,他们预见到了这个问题,并说我应该使用optionsValue
绑定:
通常,您只想使用optionsValue作为确保方法 当你更新一组时,KO可以正确地保留选择 可用选项。例如,如果您反复获取列表 “汽车”对象通过Ajax调用并希望确保所选择的汽车 保留,您可能需要将optionsValue设置为“carId”或 每个“汽车”对象具有的唯一标识符,否则KO不会 必须知道以前哪个“汽车”对象对应 哪个新的。
但遗憾的是,这不会起作用,因为它也会影响价值绑定 - 如果我将optionsValue
设置为'countryName'
,selectedCountry
将仅包含国家/地区的名称,而不是整个对象
我正在寻找一种方法来结合这些。我仍然希望value成为整个对象,但我希望选项值比较使用我指定的特定属性。基本上,有以下几点:
<select data-bind="options: availableCountries, optionsText: 'countryName', optionsComparator: 'countryName', value: selectedCountry, optionsCaption: 'Choose...'"></select>
但是,据我所知,这涉及修改value
绑定。我还有其他选择吗?我可以用其他方式解决这个问题吗?扩展器?自定义绑定处理程序?
答案 0 :(得分:3)
我已经选择了一个修复此问题的绑定,请检查我的绑定集合
演示,下拉列表位于页面末尾 http://jsfiddle.net/H8xWY/8/
https://github.com/AndersMalmgren/Knockout.Bindings
代码
ko.bindingHandlers.selected = {
init: function (element, valueAccessor, allBindingsAccessor) {
var selected = valueAccessor();
var items = ko.utils.unwrapObservable(allBindingsAccessor().options);
var key = allBindingsAccessor().optionsKey ? allBindingsAccessor().optionsKey : allBindingsAccessor().optionsText;
var observable = ko.computed({
read: function () {
var value = ko.utils.unwrapObservable(selected);
return ko.utils.arrayFirst(items, function (item) {
return value != null ? ko.utils.unwrapObservable(item[key]) == ko.utils.unwrapObservable(value[key]) : false;
});
},
write: function (value) {
writeValueToProperty(selected, allBindingsAccessor, "selected", value);
}
});
ko.applyBindingsToNode(element, { value: observable });
}
};
答案 1 :(得分:1)
我通过将getCountryByPop方法附加到我的availableCountries数组,然后调用它来设置observable的值来解决类似的问题:
availableCountries.getCountryByPop = function(pop) {
var ret;
this().forEach(function(country) {
if (country.countryPopulation == pop) {
ret = country;
}
});
return ret;
};
...
viewModel.selectedCountry(availableCountries.getCountryByPop(9));