KnockoutJS自定义绑定从多选中获取逗号分隔值

时间:2014-06-23 07:37:09

标签: jquery knockout.js

我的html中有以下select

<select class="form-control" data-bind="multiSelectCommaSeparated: CityIds, options: $root.Cities, optionsText: 'CityName', optionsValue: 'CityId', valueUpdate: 'change'" multiple="true"></select>

我正在尝试编写一个敲除自定义绑定,以便在用户在多选下拉列表中选择多个城市时,使用逗号分隔值更新CityIds observable。例如,如果我有以下select

<select id="cities" multiple="multiple">
    <option value="1">City 1</option>
    <option value="2">City 2</option>
    <option value="3">City 3</option>
    <option value="4">City 4</option>
</select>

并且用户选择前3个城市,然后我的observable应该有1,2,3。如果用户取消选择City 3,则观察结果应为1,2,这应该在用户选择/取消选择select中的任何值时立即发生。

我使用this问题引用

编写了以下自定义绑定
ko.bindingHandlers.multiSelectCommaSeparated = {
    init: function (element, valueAccessor) {
        var selMulti = $.map($(element.id + " option:selected"), function (el, i) {
            return $(el).text();
        });
        valueAccessor(selMulti);
    },
    update: function (element, valueAccessor) {
        var selMulti = $.map($(element.id + " option:selected"), function (el, i) {
            return $(el).text();
        });
        valueAccessor(selMulti);
    }
}

在上面的自定义绑定中,当我更改multi select dropdown中的选择时,不会触发更新事件。我应该在自定义绑定中更改哪些内容以实现我的要求?

1 个答案:

答案 0 :(得分:5)

我不是直接回答回答你的问题,其他人(甚至我)也可以单独回答。相反,让我提出另一种处理方法,即恕我直言,更适合Knockout的MVVM风格。

构建视图模型以将所需的CSV字符串保存为computed observable。例如:

var ViewModel = function() {
    var self = this;

    self.Cities = [
        {CityId: 1, CityName: "City 1"},
        {CityId: 2, CityName: "City 2"},
        {CityId: 3, CityName: "City 3"},
        {CityId: 4, CityName: "City 4"}
    ];

    self.SelectedCities = ko.observableArray([]);

    self.SelectedCitiesCsv = ko.computed(function(){
        return self.SelectedCities().join(",");
    });
};

您可以使用此视图进行测试:

<select class="form-control" 
        data-bind="selectedOptions: SelectedCities,
                   options: $root.Cities, 
                   optionsText: 'CityName',
                   optionsValue: 'CityId',
                   valueUpdate: 'change'"
        multiple="true"></select>

<hr />

CSV: <p data-bind="text: SelectedCitiesCsv"></p>

请参阅this fiddle了解演示。

此方法优于自定义绑定的优点包括:

  • 单元可测试;
  • 无需自定义绑定;
  • Knockout使我们的CSV字符串与View保持同步,无需自定义代码;
  • 不需要依赖jQuery,如果可能的话,利用KO让你的JS不知道实际的DOM(这再次提高了可测试性);

如果您没有为viewmodel使用构造函数,而是使用普通的javascript对象,则必须在创建具有基本属性的对象后添加计算的observables 。像这样:

var viewModel =  {
    Cities :[
        {CityId: 1, CityName: "City 1"},
        {CityId: 2, CityName: "City 2"},
        {CityId: 3, CityName: "City 3"},
        {CityId: 4, CityName: "City 4"}
    ],

    SelectedCities : ko.observableArray([])
};

viewModel.SelectedCitiesCsv = ko.computed(function(){
    return viewModel.SelectedCities().join(",");
});

或者查看this modified fiddle