【问题标题】:Knockout.js version 3.4.0 breaks jQuery Chosen plugin bindingKnockout.js 版本 3.4.0 打破了 jQuery Chosen 插件绑定
【发布时间】:2016-06-28 05:28:15
【问题描述】:

我在 Durandal 项目中工作,这意味着我使用 knockout 库。另外,我使用了 jQuery 选择的插件。

最近,我将淘汰赛从 2.0 版升级到 3.4.0 版。作为副作用,选择的插件有缺陷。它有一个错误:第一个选择始终是列表中的第一项,无论 ko 可观察对象绑定的实际值如何。

这是一个再现:

ko.bindingHandlers.chosen = {
  init: function (element) {
    ko.bindingHandlers.options.init(element);          
    $(element).chosen({ disable_search_threshold: 10 });
  },
  update: function (element, valueAccessor, allBindings) {
    ko.bindingHandlers.options.update(element, valueAccessor, allBindings);
    $(element).trigger('chosen:updated');
  }
};

ko.applyBindings({ 
  getItemAvailableAccessTypes: function(data) {
    return [
      {codeForChosen: "Open", AccessTypeName: "Open access"},
      {codeForChosen: "Restricted", AccessTypeName: "No access"}
    ];
  },
	child: {
    AccessType: ko.observable("Restricted")
  }
});
.chosen-container { width: 100% !important; }
pre { background: white; padding: 10px; color: #333; font: 11px consolas; border: 1px solid #ddd; }
<link href="https://cdnjs.cloudflare.com/ajax/libs/chosen/1.5.1/chosen.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chosen/1.5.1/chosen.jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-debug.js"></script>

<div data-bind="with: child">
<select data-bind="chosen: $parent.getItemAvailableAccessTypes($data), value: $data.AccessType,  optionsText: 'AccessTypeName',  optionsValue: 'codeForChosen'"></select>
</div>
<hr>Debug info: <pre data-bind="text: ko.toJSON($root, null, 2)"></pre>

【问题讨论】:

  • 我想我可以reproduce the issue。 (PS。如果您在问题中添加这样的repro,它会有所帮助,让其他人更容易回答。)
  • 投票,-感谢您附加的 jsFiddle,我在问题预兆处添加了对此的引用。
  • 随意内联代码,甚至可以作为堆栈片段(编辑器工具栏项之一)。然后,如果 jsfiddle 链接失效,这个问题对未来的访问者仍然有用。
  • 我不知道该怎么做。你能编辑我的问题吗?谢谢。
  • 如果你现在点击“编辑”,或者查看问题历史记录,你可以看到我是如何在 repro 中编辑的。

标签: knockout.js jquery-plugins jquery-chosen


【解决方案1】:

我不熟悉 jQuery.chosen 插件,但我可能有一个修复。

我认为&lt;select&gt; 元素有两种显示其值的方式:

  1. 它位于 select 元素本身的 value 属性中,
  2. 还可以有一个带有selected 属性的option 绑定(通常表示初始选择)。

我注意到淘汰赛没有设置selected 属性。当我尝试插件是否能够正确设置带有selected 的初始选择时,结果证明是。

现在,挑战是在最初选择的选项中包含selected 属性。我认为init 方法将是最好的地方,但事实证明默认绑定不会创建选项元素,直到update...It even deletes any elements that are already there

所以,最终,我将逻辑放入 update 绑定中,一切似乎都按预期工作。

请不要说您可能想做一些进一步的测试。另外,我相信您需要返回原始绑定的返回值,因为这让淘汰赛知道后代绑定已得到处理。此外,您可能需要查看 custom disposal logic 以确保您的 jQuery 小部件在从 DOM 中删除选择后被销毁。

ko.bindingHandlers.chosen = {
  init: function(element) {
    var optionsReturnValue = ko.bindingHandlers.options.init(element);

    $(element).chosen({
      disable_search_threshold: 10
    });

    return optionsReturnValue;
  },
  update: function(element, valueAccessor, allBindings) {
    ko.bindingHandlers.options.update(element, valueAccessor, allBindings);

    var currentValue = ko.unwrap(allBindings.get("value"));
    var selectedOption = element.querySelector("[value=" + currentValue + "]");
    if (selectedOption) {
      selectedOption.setAttribute("selected", "selected");
    }
    
    $(element).trigger('chosen:updated');
  }
};

ko.applyBindings({
  getItemAvailableAccessTypes: function(data) {
    return [{
      codeForChosen: "Open",
      AccessTypeName: "Open access"
    }, {
      codeForChosen: "Restricted",
      AccessTypeName: "No access"
    }];
  },
  child: {
    AccessType: ko.observable("Restricted")
  }
});
.chosen-container {
  width: 100% !important;
}
pre {
  background: white;
  padding: 10px;
  color: #333;
  font: 11px consolas;
  border: 1px solid #ddd;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/chosen/1.5.1/chosen.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chosen/1.5.1/chosen.jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-debug.js"></script>

<div data-bind="with: child">
  <select data-bind="chosen: $parent.getItemAvailableAccessTypes($data), value: $data.AccessType,  optionsText: 'AccessTypeName',  optionsValue: 'codeForChosen'"></select>
</div>
<hr>Debug info: <pre data-bind="text: ko.toJSON($root, null, 2)"></pre>

【讨论】:

  • 谢谢大家,它运作良好。我希望没有我跳过的错误。我努力理解您对解决方案的解释,但没有成功。如果你能改进它——我会很高兴的。而且,你知道为什么这个问题只发生在这个版本的淘汰赛中吗?
  • 这两个版本之间的options绑定有很多变化...在2.2.0中,我可以看到ko.utils.setOptionNodeSelectionState被每个update调用,这似乎没有发生在 3.4.0 ......如果我能找到时间,我可能会在我的答案中添加更多解释。
猜你喜欢
  • 1970-01-01
  • 2016-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-11
  • 1970-01-01
  • 2019-04-18
  • 1970-01-01
相关资源
最近更新 更多