【问题标题】:Select2 allowclear and knockout.jsSelect2 allowclear 和 knockout.js
【发布时间】:2014-07-12 11:29:10
【问题描述】:

我通过这个简单的绑定使用 select2 和 knockoutJs:

ko.bindingHandlers.select2 = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        var options = ko.toJS(valueAccessor()) || {};
        setTimeout(function () {
            $(element).select2(options);
        }, 0);
    }
};

标记:

<select class="select2" style="width:100%" data-bind="optionsCaption: '',options: $root.items,optionsText: 'description',optionsValue: 'id', value: $root.selectedItem,select2: { placeholder: 'Select an item...',allowClear: true }"></select>

有效!现在我在 Select2 中启用了allowClear 选项,以将下拉列表清除为Select an item... 之类的占位符值。

如果我点击x 图标下拉菜单正确设置占位符但敲除不会更新可观察的绑定值!

我想我必须更改自定义绑定添加如下内容:

setTimeout(function () {
    $(element).select2(options).on("select2-removed", function (e) {
       ko.bindingHandlers.value.update(element, function () { return ''; });
    });
...

但它不会工作!

【问题讨论】:

  • 您能否提供一个带有您的代码的jsfiddle
  • setTimeout 是怎么回事?另外,我只能看到“init”实现,如果你有的话,你能在 bindingHandler 中显示你的“update”实现吗?

标签: javascript jquery knockout.js


【解决方案1】:

有几个问题。

1) bindinghandler 中的update 用于根据值变化更新 DOM,您永远不应该定义具有改变模型能力的 update 回调。

正确的做法是,在定义一个新的 bindinghandler 时,使用init 回调将所有change 事件与模型挂钩,update 回调只是一个 DOM 绘制例程

如果您的init 提供了DOM 绘图(如select2 提供),则无需定义update 回调。

因此 ko.bindingHandlers.value.update(element, function () { return ''; }); 行仅重绘 DOM,它不会做你想做的事。

2) 您创建的select2 绑定有一些漏洞。

  • 首先,value 绑定不知道select2 绑定的存在,这就是你挣扎的地方。
  • 其次,您的select2 绑定必须等待其他绑定(options 绑定)完成DOM 创建,这就是您使用setTimeout 的原因。但是ko提供了一种定义绑定顺序的方法,看ko value绑定的源代码,定义为'after': ['options', 'foreach']
  • 第三,您的 select2 不响应外部更改。例如,如果您有另一个 UI 来更新 $root.selectedItem(一个普通的选择列表),则该 UI 引发的更改不会同步回您的 select2。

解决方案

定义select2绑定基于现有的value绑定(才发现不需要),并挂钩所有更改事件。

  • 我们不需要"select2-removed" 事件,只需要"change" 事件。
  • select2提供了所有的绘图,我们不需要update回调。
  • 使用标志 shouldIgnore 打破值订阅者和 select2 更改事件处理程序之间的循环。

http://jsfiddle.net/huocp/8N3zX/6/ http://jsfiddle.net/huocp/8N3zX/9/

ko.bindingHandlers.valueSelect2 = {
    'after': ['options'],
    'init': function(element, valueAccessor, allBindings) {
        // kind of extend value binding
        // ko.bindingHandlers.value.init(element, valueAccessor, allBindings);

        var options = allBindings.get('select2Options') || {};
        $(element).select2(options);

        var value = valueAccessor();
        // init val
        $(element).val(ko.unwrap(value)).trigger("change");

        var changeListener;
        if (ko.isObservable(value)) {
            var shouldIgnore = false;
            changeListener = value.subscribe(function(newVal) {
                if (! shouldIgnore) {
                  shouldIgnore = true;
                  // this is just select2 syntax
                  $(element).val(newVal).trigger("change");
                  shouldIgnore = false;
                }
            });

            // this demo only works on single select.
            $(element).on("change", function(e) {
                if (! shouldIgnore) {
                    shouldIgnore = true;
                    if (e.val == '') {
                        // select2 use empty string for unselected value
                        // it could cause problem when you really want '' as a valid option
                        value(undefined);
                    } else {
                        value(e.val);
                    }
                    shouldIgnore = false;
                }
            });
        }

        ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
            if (changeListener) changeListener.dispose();
            $(element).select2("destory");
        });
    }
};

【讨论】:

猜你喜欢
  • 2013-11-14
  • 1970-01-01
  • 1970-01-01
  • 2023-03-03
  • 2015-03-19
  • 2014-03-20
  • 2014-02-03
  • 2023-04-09
  • 1970-01-01
相关资源
最近更新 更多