Select2 with ajax, multiple and knockout binding 不将对象保存到 selectedOptions

Posted

技术标签:

【中文标题】Select2 with ajax, multiple and knockout binding 不将对象保存到 selectedOptions【英文标题】:Select2 with ajax, multiple and knockout binding not saving objects to selectedOptions 【发布时间】:2015-09-11 05:35:47 【问题描述】:

我正在评估与我们从 v3.5.x 升级相关的 select2 v4.0。我们将它与淘汰赛 v3.5.2 一起使用。我们的场景是我们希望允许用户根据来自 ajax 调用的 js 对象选择多个选项。 selectedoptions 绑定应该将整个 js 对象存储在其绑定的 observablearray 中,而不仅仅是 id 列表。

在我的测试中,这是我发现的

这是一个带有预定义选项列表的 select2。每个选项都有一个 id、text 和 displayText 属性。结果是 multipleSelectedObjects 可观察数组最终拥有一个包含整个 js 对象的数组,这是我所期望的,因为我没有设置 optionsValue 参数

<select class="multipleSelect" data-bind="options: multipleOptions, selectedOptions: multipleSelectedObjects, optionsText: 'displayText', select2v4: multipleOptionsSetup" style="width: 200px">

这是一个带有预定义选项列表的 select2。每个选项都有一个 id、text 和 displayText 属性。结果是 multipleSelectedValue 可观察数组最终有一个整数数组,表示所选 js 对象的 id,这是我所期望的,基于我设置 optionsValue 参数的事实

<select class="multipleSelect3" data-bind="options: multipleOptions, selectedOptions: multipleSelectedValue, optionsText: 'text', optionsValue: 'id', select2v4: multipleOptionsSetup" style="width: 200px">

这是一个 select2,它使用 ajax 选项进行服务调用以返回选项。返回的每个选项都有一个 id、text 和 displayText 属性。结果是 selectedItems 可观察数组最终具有一个整数数组,表示所选 js 对象的 id。这不是我所期望的。我尝试只设置 optionsText 属性,就像我对上面第一个 select2 所做的那样,但这并没有什么不同

<select id="select2Input" data-bind="selectedOptions: selectedItems, select2v4: selectSetup" style="width: 400px">

我认为这可能是一个 select2 问题,但我不确定。我们的 select2v4 绑定处理程序如下所示。在最后一个场景中,当淘汰赛命中 selectedOptions 部分时,该值是一个字符串,这让我认为 select2 没有设置为在使用 ajax 时传递整个对象。其他人经历过这个吗?这是一个错误还是设计使然?

// NOTE: this binding handler is made for select2 version 4.0

 ko.bindingHandlers.select2v4 =  

     init: function (element, valueAccessor, allBindingsAccessor)  

         var bindingValue = ko.unwrap(valueAccessor()); 

         var allBindings = allBindingsAccessor(); 

         var valueDataChange; 

         // Observe external data changes; set data on change 

         if (ko.isObservable(allBindings.valueData))  // special data binding 

             var onChange = false; 

             allBindings.valueData.subscribe(function (value)  // subscribe to external data changes 
                 if (onChange) return; // ignore if on change to prevent recursion 
                 $(element).select2("data", value, false); // set data explicitly; do not trigger change ); 

             if (ko.isWritableObservable(allBindings.valueData))  

                 valueDataChange = function ()  

                     onChange = true; // suppress valueData subscription 

                     allBindings.valueData($(element).select2("data")); 

                     onChange = false; 

                 ; 

                 $(element).on("change", valueDataChange); // update observable on data change 

              

          

         // Observe external value changes 

         else if (ko.isObservable(allBindings.value))  // input or single select with observable value binding 

             allBindings.value.subscribe(function (value)  // subscribe to external value changes 

                 if (typeof value === "string")  // optionsValue or tags specified 

                     if (bindingValue.tags)  // tags specified 

                         value = value.split(bindingValue.separator || ','); // split on value separator 

                      

                     $(element).val(value); // set val to allow select2 to resolve data from values; do not trigger change 

                  
                 else  // optionsValue not specified, value is complex data 

                     $(element).select2("data", value, false); // set data explicitly; do not trigger change 

                  

             ); 

          

 // Observe external selection changes 

         else if (ko.isObservable(allBindings.selectedOptions))  // multiselect with observable selection binding 

             allBindings.selectedOptions.subscribe(function (value)  // subscribe to external selection changes 

                 if (value.length > 0 && typeof value[0] === "string")  // optionsValue specified 

                     $(element).val(value); // set val to allow select2 to resolve data from values; do not trigger change 

                  
                 else  // optionsValue not specified, value is complex data 

                     $(element).select2("data", value, false); // set data explicitly (only works if complex data object has 'id' property); do not trigger change 

                  

             ); 

          

         // Destroy select2 on element disposal 

         ko.utils.domNodeDisposal.addDisposeCallback(element, function ()  

             $(element).select2('destroy'); 

             if (valueDataChange != null)  

                 $(element).off("change", valueDataChange); 

              

         ); 

         // Apply select2 and initialize data; delay to allow other binding handlers to run 

         setTimeout(function ()  

             // Apply select2 

             $(element).select2(bindingValue); 

             // Initialize data 

             if ("valueData" in allBindings)  

                 $(element).select2("data", ko.unwrap(allBindings.valueData), false); 

              

         , 0); 

       

  ;

【问题讨论】:

我遇到了同样的问题,select2 没有将对象返回到 selectedOptions 变量。如果我不应用 select2 而只使用敲除,它可以完美运行,但看起来不太好。 【参考方案1】:

与之前的版本相比,select2 v4 的内部工作方式发生了许多重大变化。其中之一是 select2 在使用 ajax 加载数据的情况下如何存储选定的对象(又名 typeahead)。我的一位同事发现,在这种情况下,所选对象存储在只读集合中,并且在进行更改时不会正确通知,而且正常绑定无法按预期工作。正如我们所发现的,绑定到 selectedOptions 不会导致对象列表,而是 ids。他提出了如下所示的 select2 绑定处理程序,该处理程序将处理常规选择样式绑定并添加一个名为 selectData 的新绑定,如果您使用 ajax 远程数据加载,它将为您提供选定对象的列表。如果您使用 ajax 加载数据并希望获取所选对象的列表而不是 id,则仅需要 selectData 绑定,否则您可以绑定到 value 或 selectedOptions 并且设置类型将按预期工作。

<select id="select2Input" data-bind="select2Data: selectedItems, select2: selectSetup" style="width: 400px"></select>

https://github.com/shaftware/knockout-select2

【讨论】:

【参考方案2】:

您好,您是否尝试过使用 optionsAfterRender 来设置值?

这对我有用:

<select id="selectArticles" multiple
 data-bind="options: availableArticles, selectedOptions: selectedArticles,
 optionsText: function(item)return item.title,
 optionsAfterRender: function(option, item)option.value = item">
</select>

workding fiddle

【讨论】:

这不是完全相同的场景。你在你的和我的中设置一个预定义的选项列表,我正在使用 ajax 进行预输入搜索。我有一个类似的示例,其中我像您一样定义了一个静态选项列表,整个绑定按预期工作,并将 js 对象放在 selectedOptions 列表中。如果我设置了完全相同的绑定,但去掉了 options 参数并在 select2 设置中使用了 ajax,那么选择一个项目会将其 id 放入 selecteditems 列表而不是 js 对象中。 看来我不太明白你在做什么,抱歉。在我的项目中,我还通过 ajax 调用(不使用 select2)加载可用对象并将它们提供给 observableArray。我还将可用对象替换为全新的对象(来自 ajax 请求),仅保留已选择的项目。你能试着解释一下你想做什么吗? 对不起,我想应该更具描述性。当我说我使用 ajax 时,我指的是 select2 支持的内置预输入搜索。这是我正在使用的设置类型的示例。我认为在这种情况下 select2 可能会做一些不同的事情,因为它试图保存到 observablearray。 我的设置类似于 select2 示例的加载远程数据部分。 select2.github.io/examples.html 你不能只使用 ajax 调用的 processResults 部分来完成我在示例中使用 observableArray 所做的事情吗?当我有时间时,我会尝试构建一个可以做到这一点的小提琴。

以上是关于Select2 with ajax, multiple and knockout binding 不将对象保存到 selectedOptions的主要内容,如果未能解决你的问题,请参考以下文章

Select2 with ajax, multiple and knockout binding 不将对象保存到 selectedOptions

java 来自http://stackoverflow.com/questions/23720140/using-factory-pattern-with-multiple-arguments-in-

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

Select2 未通过 AJAX 获取数据

Select2 ajax:在编辑模式下预选数据

Select2:使用 AJAX 未显示结果