Knockout.JS与bootstrap selectpicker

时间:2014-02-24 20:40:46

标签: javascript twitter-bootstrap knockout.js

我正在尝试使用Bootstrap Selectpicker和knockout.js。已经存在一个适用于selectpicker(seen here)的多选版本的自定义绑定,但是我需要它才能使用单一选择版本。我认为这就像将ko.observableArray更改为ko.observable并删除multiple属性一样简单 - 但似乎并非如此。关于如何使这个工作的任何想法?

Fiddle with the binding and my updated code

3 个答案:

答案 0 :(得分:13)

编辑请参阅下面的备用解决方案

问题在于你的selectPicker.init函数。

您需要调用选项绑定,而不是值绑定。 options.init设置初始内部状态,当这绕过options.update函数将重置该值。

// regular select and observable so call the default value binding
ko.bindingHandlers.value.init(element, valueAccessor, allBindingsAccessor);

更改为

// regular select and observable so call the default value binding
ko.bindingHandlers.options.init(element, valueAccessor, allBindingsAccessor);

修改

好的,我把你的样本带回基础,使用标准选项绑定来正常选择工作。

然后仅使用selectpicker绑定进行初始化和刷新。它将自己与选择同步。

在Knockout 3之前,如果元素上的任何绑定导致更新(如更新选项,值或selectedOptions),则会调用selectPicker更新函数。使用Knockout 3,绑定现在可以独立启动(好东西),但是当选项或值/ selectedOptions发生更改时,您现在需要使用订阅来获得通知。

我认为你会发现这个现在变得更简单了,你的自定义绑定中的单选和多选之间没有区别。现在,如果更新了teamItems或itemID observable,这将有效。

<强> HTML          

<!-- Multiple Select -->
<select data-bind="selectedOptions: teamIDs, 
                   options: teamItems, 
                   optionsText: 'text', 
                   optionsValue : 'id', 
                   selectPicker: {}" multiple="true"></select>

<强> JAVASCRIPT

ko.bindingHandlers.selectPicker = {
  after: ['options'],   /* KO 3.0 feature to ensure binding execution order */
  init: function (element, valueAccessor, allBindingsAccessor) {
     var $element = $(element);
     $element.addClass('selectpicker').selectpicker();

     var doRefresh = function() {
         $element.selectpicker('refresh');
     },  subscriptions = [];

     // KO 3 requires subscriptions instead of relying on this binding's update
     // function firing when any other binding on the element is updated.

     // Add them to a subscription array so we can remove them when KO
     // tears down the element.  Otherwise you will have a resource leak.
     var addSubscription = function(bindingKey) {
         var targetObs = allBindingsAccessor.get(bindingKey);

         if ( targetObs && ko.isObservable(targetObs )) {
            subscriptions.push( targetObs.subscribe(doRefresh) );
         }
     };

     addSubscription('options');
     addSubscription('value');           // Single
     addSubscription('selectedOptions'); // Multiple

     ko.utils.domNodeDisposal.addDisposeCallback(element, function() { 
         while( subscriptions.length ) {
             subscriptions.pop().dispose();
         }
     } );
   },
   update: function (element, valueAccessor, allBindingsAccessor) {
   }
 };

答案 1 :(得分:2)

Knockout对计算绑定提供了出色而强大的支持(例如ko.bindingHandlers.selectPicker = { after: ['options', 'value', 'selectedOptions'], init: function (element, valueAccessor, allBindingsAccessor) { $(element).addClass('selectpicker').selectpicker(); }, update: function (element, valueAccessor, allBindingsAccessor) { /* KO 3.3 will track any bindings we depend on and call us when any of them changes */ allBindingsAccessor.get('options'); allBindingsAccessor.get('value'); allBindingsAccessor.get('selectedOptions'); $(element).selectpicker('refresh'); } }; ),当前的答案无法支持这些。

为了进一步改进RobertSlanley的答案,并基于Knockout's documentation,我创建了以下绑定。

只要我们在update方法中访问它们,Knockout就会自己处理可观察的订阅。 这意味着我们可以删除订阅,只关注我们真正想做的事情:

{{1}}

Here's a demo fiddle

答案 2 :(得分:0)

不幸的是我还不能对上述答案发表评论,但HTML部分有一点错误:

选定的值绑定应为selectedOptions而不是selectOptions

HTML

<!-- Multiple Select -->
<select data-bind="selectedOptions: teamIDs, 
               options: teamItems, 
               optionsText: 'text', 
               optionsValue : 'id', 
               selectPicker: {}" multiple="true"></select>