Select2 with ajax,多个和敲除绑定不将对象保存到 selectedOptions

Select2 with ajax, multiple and knockout binding not saving objects to selectedOptions

我正在评估 select2 v4.0 与我们从 v3.5.x 升级的关系。我们将其与 knockout v3.5.2 一起使用。我们的场景是,我们希望允许用户根据来自 ajax 调用的 js 对象 select 多个选项。 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 selected,这是我根据设置 optionsValue 参数

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

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

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

我认为这可能是一个 select2 问题,但我不确定。我们的 select2v4 绑定处理程序如下所示。在最后一个场景中,当 knockout 命中 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); 

      } 

  };

您好,您尝试过使用 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

与之前的版本相比,select2 v4 的内部工作方式发生了一些重大变化。其中之一是 select2 在使用 ajax 加载数据(也称为提前输入)的情况下如何存储 selected 对象。我的一个同事能够弄清楚,在那种情况下,selected 对象存储在只读集合中,并且在进行更改时不会正确通知,而且正常绑定不会按预期工作。正如我们所发现的,绑定到 selectedOptions 并不会生成对象列表,而是生成 ID。他想出了下面显示的 select2 的绑定处理程序,它将处理常规 select 样式绑定并添加一个名为 selectData 的新绑定,这将为您提供 selected 对象,如果您使用 ajax 进行远程数据加载。如果您使用 ajax 加载数据并且想要获取 selected 对象的列表而不是 id,则只需要 select 数据绑定,否则您可以绑定到值或selectedOptions 和设置类型将按预期工作。

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

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