简体   繁体   English

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

[英]KnockoutJS custom binding to get comma separated values from multi select

I am having the following select in my html: 我在html中select了以下内容:

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

I am trying to write a knockout custom binding to update the CityIds observable with comma separated values whenever user selects multiple cities in the multi select drop down. 我试图编写一个敲除自定义绑定,以便每当用户在多选下拉列表中选择多个城市时,用逗号分隔的值更新可观察到的CityIds For example if I have the following select : 例如,如果我有以下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>

and the user selects first 3 cities, then my observable should have 1,2,3 . 并且用户选择了前3个城市,那么我的可观察值应为1,2,3 If the user de-selects City 3 , then the observable should have 1,2 and this should happen as soon soon as the user selects/de-selects any value in the select . 如果用户去选择City 3 ,则观察到的应该有1,2 ,这应尽快一旦用户选择发生/取消选择在任何价值select

I have written the following custom binding by using reference from this question: 通过使用来自问题的引用,我编写了以下自定义绑定:

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);
    }
}

In the above custom binding, the update event is not firing when I change my selection in the multi select dropdown . 在上述自定义绑定中,当我在multi select dropdown更改选择时,不会触发update事件。 What should I change in the custom binding to achieve my requirement? 我应该在自定义绑定中进行哪些更改以实现我的要求?

I'm not quite straight up answering your question, someone else (or even I) may do so in a separate answer. 我不是很直接回答您的问题,其他人(甚至我)可能会在另一个答案中回答。 Instead, let me propose an alternative way to handle this, which is IMHO better suited to Knockout's MVVM style. 相反,让我提出一种替代方法来处理此问题,它是IMHO更好地适合Knockout的MVVM样式。

Construct your view model to hold the CSV string you want as a computed observable . 构造视图模型以将所需的CSV字符串保存为可计算的observable For example: 例如:

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(",");
    });
};

You can test this with this View: 您可以使用以下视图对此进行测试:

<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>

See this fiddle for a demo. 看到这个小提琴演示。

The advantages of this approach over a custom binding include: 与自定义绑定相比,此方法的优点包括:

  • Unit testable; 可单元测试;
  • No custom bindings needed; 无需自定义绑定;
  • Knockout keeps our CSV string in synch with the View, no custom code needed; 淘汰赛使我们的CSV字符串与View保持同步,不需要自定义代码;
  • No dependency on jQuery needed, if possible leverage KO to keep your JS ignorant of the actual DOM (which again improves testability); 无需依赖jQuery,如果可能的话,可以利用KO使您的JS对实际的DOM不了解(这再次提高了可测试性);

In the case where you're not using constructor functions for your viewmodels, but plain javascript objects, you have to add computed observables after creating the object with the base properties. 如果您的视图模型没有使用构造函数,而是使用普通的javascript对象,则必须创建具有基本属性的对象添加计算的可观察对象。 Something like this: 像这样:

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(",");
});

Or see this modified fiddle . 或看这个修饰的小提琴

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM