【问题标题】:Knockout.JS with bootstrap selectpicker带有引导选择器的 Knockout.JS
【发布时间】:2014-03-26 18:01:56
【问题描述】:

我正在尝试将Bootstrap Selectpicker 与 knockout.js 一起使用。已经有一个自定义绑定适用于 selectpicker 的多选版本 (seen here),但我需要它与单选版本一起使用。我认为这将像将ko.observableArray 更改为ko.observable 并删除multiple 属性一样简单——但情况似乎并非如此。关于如何让它发挥作用的任何想法?

Fiddle with the binding and my updated code

【问题讨论】:

  • 我不明白你的演示中有什么不起作用。你能更明确一点吗?从我所见,所选值反映了您的下拉选择是什么......
  • 问题在于初始值(在演示中,teamID)。在teamID 中设置为 2,但选择最初显示为 1。

标签: javascript twitter-bootstrap knockout.js


【解决方案1】:

编辑替代解决方案见下文

问题在于您的 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 中,绑定现在可以独立触发(好事),但您现在需要使用订阅来在选项或 value/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) {
   }
 };

【讨论】:

  • 感谢您的帮助。这似乎对初始设置有效,但现在teamID 值在选择选项更改时不会更新。关于为什么会这样的任何想法? jsfiddle.net/9EQeg/34
  • +1 谢谢,这是一种享受! html data-bind 属性中的一个小怪癖是“selectPicker”的位置必须在“options”之后,否则最初不会显示集合中的最后一项,而是在选择另一个项之后。
  • 在 KO 3 下,您可以向绑定处理程序添加一个 'after' 属性,并且 KO 将确保在您的处理程序之前调用这些处理程序,而不管数据绑定属性中的顺序如何。但你对 KO 2.x 是正确的
  • 实际上,KO 3 会跟踪您在更新函数中使用了哪些绑定(请参阅knockoutjs.com/documentation/custom-bindings.html)。您的方法对于计算表达式失败(请参阅jsfiddle.net/c2gbak5m
【解决方案2】:

Knockout 对计算绑定(例如 item().children.length &gt; foo().maxChildren)具有出色而强大的支持,而当前的答案不支持这些。

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

只要我们在更新方法中访问它们,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');
    }
};

Here's a demo fiddle

【讨论】:

  • 但是您正在将您的值和选项绑定到非可观察实体。 dc.item().A = "A" 不会更新选择器。如果字段“A”是可观察的,那么我的方法仍然有效。
  • 罗伯特,您的方法未能接受 KO 对可观察表达式的方法。 KO 最强大的功能是计算绑定,例如data-bind="text: item().isVisible ? 'foo' : 'bar'"。通过您的方法,您可以在初始化时订阅绑定的结果,而 KO 中的内置绑定会跟踪整个表达式的更改。我并不是说您的解决方案是错误的,只是不习惯
  • 这是对我有用的答案,不确定我是否完全理解接受的答案和这个答案之间的区别,但是谢谢!
【解决方案3】:

很遗憾,我还不能对上面的答案发表评论,但是 HTML 部分有一个小错误:

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

HTML

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-17
    • 1970-01-01
    • 2013-10-11
    • 1970-01-01
    • 2020-11-12
    • 1970-01-01
    • 1970-01-01
    • 2013-12-14
    相关资源
    最近更新 更多