将 select2 与淘汰赛绑定

Posted

技术标签:

【中文标题】将 select2 与淘汰赛绑定【英文标题】:Binding select2 with knockout 【发布时间】:2016-10-26 09:17:30 【问题描述】:

我是淘汰赛的新手,我正在尝试让我的 select2 与我的淘汰赛绑定很好地配合。

我要做的就是将帐户数组绑定到我的 select2(这有效),然后 在绑定发生时设置初始值。由于某种原因,我无法使其正常工作。还注意到最初调用了 init 和 update 函数,但是每当我更改 select2 下拉列表的值时,都不会触发更新函数。

任何帮助将不胜感激。

HTML

 <div class="col-sm-12 col-md-3">
   <fieldset class="form-group">
     <label data-bind="attr:for:'job'+laborDetailId()">Job</label>
     <select class="select2" data-bind="attr:id:'job'+laborDetailId(),updateaccountdropdown: value:account(),data:accounts,width:'100%'">
     </select>
   </fieldset>
 </div>

JS

var accounts = ["id":-1,"text":"","description":null, "id":25,"text":"J13002","description":null, "id":28,"text":"J13053","description":null];

var LaborListModel = function(laborModels) 
  var self = this;

  //contains all labor models
  self.labordetails = ko.observableArray(laborModels);
  self.selectedAccount = ko.observable();

  //bindings
  ko.bindingHandlers.updateaccountdropdown = 
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) 
        ko.utils.domNodeDisposal.addDisposeCallback(element, function() 
            $(element).select2('destroy');
        );

        var allBindings = allBindingsAccessor(),
            select2 = ko.utils.unwrapObservable(allBindings.updateaccountdropdown);
        $(element).select2(select2);
    ,
    update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) 
        var allBindings = allBindingsAccessor();
        if ("value" in allBindings) 
            var val = ko.utils.unwrapObservable(valueAccessor());
            $(element).val(val.id).trigger('change');
        
    
  ;


getAllLaborDetails().done(function(result) 
   loadAccounts().done(function(_accounts) 
     accounts = _accounts;
     for (var i = 0; i < result.length; i++) 
       //LaborModel
       var laborDetails = [];
       laborDetails.push(new LaborModel(
         result[i].labourDetailId,
         result[i].account,
         result[i].categoryModel,
         result[i].description,
         result[i].timeStamp,
         result[i].hour
       ));
     
     var vm = new LaborListModel(laborDetails);
     ko.applyBindings(vm);
   );
)

【问题讨论】:

官方 github wiki 现在有很好的指针(对于 select2 4.x 和 3.x)-github.com/select2/select2/wiki/Knockout.js-Integration @shad0w_wa1k3r,不幸的是,不再是了。 【参考方案1】:

希望这个“select2”自定义绑定对您有所帮助:

ko.bindingHandlers.select2 = 
    after: ["options", "value"],
    init: function (el, valueAccessor, allBindingsAccessor, viewModel) 
        $(el).select2(ko.unwrap(valueAccessor()));
        ko.utils.domNodeDisposal.addDisposeCallback(el, function () 
            $(el).select2('destroy');
        );
    ,
    update: function (el, valueAccessor, allBindingsAccessor, viewModel) 
        var allBindings = allBindingsAccessor();
        var select2 = $(el).data("select2");
        if ("value" in allBindings) 
            var newValue = "" + ko.unwrap(allBindings.value);
            if ((allBindings.select2.multiple || el.multiple) && newValue.constructor !== Array) 
                select2.val([newValue.split(",")]);
            
            else 
                select2.val([newValue]);
            
        
    
;

$(document).ready(function()
    var data = ko.observableArray([id: 1, text: "A", id: 2, text: "B"]);
    var value = ko.observable();
    ko.applyBindings(data: data, value: value);
);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.1/js/select2.full.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.1/css/select2.css" />

<span>Selected value: </span>
<span data-bind="text: value"></span>

<div style="width: 350px; margin-top: 20px;">
   <select style="width: 100%;" data-bind="value: value, valueAllowUnset: true, options: data, optionsText: 'text', optionsValue: 'id', select2:  placeholder: 'Select an option...', allowClear: true "></select>
</div>

感谢:

Select2 团队 (https://github.com/select2/select2/issues/3116) *** 社区 (Select2 4.0.0 initial value with Ajax, Knockout/Select2: Triggering select2 to update based on an observable option updating)

【讨论】:

【参考方案2】:

根据select2 wiki on github 的这个例子,他们提供了Knockout binding handler,它对我有用。

ko.bindingHandlers.select2 = 
    init: function (el, valueAccessor, allBindingsAccessor, viewModel) 
        ko.utils.domNodeDisposal.addDisposeCallback(el, function () 
            $(el).select2('destroy');
        );

        var allBindings = allBindingsAccessor(),
            select2 = ko.utils.unwrapObservable(allBindings.select2);

        $(el).select2(select2);
    ,
    update: function (el, valueAccessor, allBindingsAccessor, viewModel) 
        var allBindings = allBindingsAccessor();

        if ("value" in allBindings) 
            if ((allBindings.select2.multiple || el.multiple) && allBindings.value().constructor != Array) 
                $(el).val(allBindings.value().split(',')).trigger('change');
            
            else 
                $(el).val(allBindings.value()).trigger('change');
            
         else if ("selectedOptions" in allBindings) 
            var converted = [];
            var textAccessor = function (value)  return value; ;
            if ("optionsText" in allBindings) 
                textAccessor = function (value) 
                    var valueAccessor = function (item)  return item; 
                    if ("optionsValue" in allBindings) 
                        valueAccessor = function (item)  return item[allBindings.optionsValue]; 
                    
                    var items = $.grep(allBindings.options(), function (e)  return valueAccessor(e) == value );
                    if (items.length == 0 || items.length > 1) 
                        return "UNKNOWN";
                    
                    return items[0][allBindings.optionsText];
                
            
            $.each(allBindings.selectedOptions(), function (key, value) 
                converted.push( id: value, text: textAccessor(value) );
            );
            $(el).select2("data", converted);
        
        $(el).trigger("change");
    
;

实际上,这是他们提供的原始版本,但我不得不更改一行以使其选择已选择的选项。

我替换了这一行

$(el).select2("data", converted);

$(el).val(converted);

我认为这是因为 select2 版本存在一些差异。 您可以尝试这两种解决方案,看看哪种方案适合您。

html 如下

 <select data-bind="selectedOptions: SelectedTags, options: AllTags,  valueAllowUnset: true, optionsText:'Text', optionsValue: 'Value', 
         select2: placeholder: 'select tag', allowClear: true, multiple:'multiple'" multiple></select>

更新 select2 版本 4 以前的解决方案适用于版本 4 以下的 select2 版本。对于 Select2 版本 4,我创建了其他一些 binding handler here it is

【讨论】:

以上是关于将 select2 与淘汰赛绑定的主要内容,如果未能解决你的问题,请参考以下文章

在 jQuery 对话框中淘汰 'with' 绑定和 select2

Select2 用字符串覆盖淘汰赛 observableArray

淘汰赛 3.1:Select2 无法与 valueAllowUnset 一起正常工作

Select2 Js 下拉菜单在 durandal Js 中不起作用

带有 ajax 的淘汰赛3+select2 (v4)

如何清除 Select2 中的选定值