【问题标题】:Select2 with ajax, multiple and knockout binding not saving objects to selectedOptionsSelect2 with ajax, multiple and knockout binding 不将对象保存到 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 而只使用敲除,它可以完美运行,但看起来不太好。

标签: knockout.js jquery-select2 jquery-select2-4


【解决方案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 所做的事情吗?当我有时间时,我会尝试构建一个可以做到这一点的小提琴。
    猜你喜欢
    • 2014-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-07
    • 2012-08-30
    • 2012-02-19
    • 1970-01-01
    • 2022-12-02
    相关资源
    最近更新 更多