2014-07-12 36 views
2

我使用选择2和knockoutJs这个简单的绑定:选择二allowclear和knockout.js

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图标下拉菜单正确设置占位符,但敲除不会更新可观察的绑定值!

我想我已经改变custombinding将是这样的:

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

,但它不会工作!

+1

能否请您提供的jsfiddle与您的代码 –

+0

与setTimeout的是什么?另外,我只能看到“init”的实现,你是否也可以在bindingHandler中显示你的“更新”实现? –

回答

2

有几个问题。

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提供了一种定义绑定顺序的方法,只需看绑定的源代码,它的定义为'after': ['options', 'foreach']
  • 第三,你的select2不响应外部变化。例如,如果您有另一个用户界面来更新$root.selectedItem(正常选择列表),则该用户界面引发的更改不会同步回您的select2。

解决方案

定义基于现有value结合select2结合 (刚刚发现它并不需要),并挂接所有更改事件。

  • 我们不需要"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"); 
     }); 
    } 
}; 
+0

要遵循ko练习,changeListener的内容应该转到'valueSelect2.update'回调。 http://jsfiddle.net/huocp/8N3zX/10/ – huocp