淘汰赛:我如何设置选项框的值,其选项是javascript对象?

时间:2013-01-21 21:30:18

标签: javascript knockout.js

我有一个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绑定。我还有其他选择吗?我可以用其他方式解决这个问题吗?扩展器?自定义绑定处理程序?

2 个答案:

答案 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));

jsfiddle.net/6BaP5/