【发布时间】:2013-01-21 01:15:25
【问题描述】:
我有一个用于 Knockout.js 的 very simple Bootstrap Typeahead binding (jsFiddle),如下所示:
ko.bindingHandlers.typeahead = {
init: function (element, valueAccessor) {
var $e = $(element),
source = valueAccessor();
$e.typeahead({
source: source,
minLength: 0
});
},
};
它的用法很简单:
<input data-bind='typeahead: source, value: item,
valueUpdate: "afterkeydown"' />
绑定在jsFiddle 中按预期工作。但是,当使用 RequireJS 加载时,它并不总是按预期工作。由于 Knockout 和 jQuery 并行加载,似乎存在竞争条件。
如果我查看绑定输入元素的 change 事件处理程序,如果 jQuery 是处理程序,则绑定按预期工作。如果 Knockout 是 change 事件的处理程序,例如,如果您键入“alp”,并且 Typeahead 建议“Alpha”,并且您从 Typeahead 下拉列表中选择“Alpha”,那么 <input> 元素将显示选定的文本(“Alpha”),但绑定的 observable 将是“alp”。
在当前系统中,Typeahead 绑定无法直接修改给定的 observable,因此传递 { source: src, observable: item } 无法解决问题。这个Typeahead绑定的作用只是更新绑定输入区的内容。
我已经尝试过从绑定中触发相关事件,例如“keydown”、“keypress”和“keyup”,但由于显而易见的原因,这不是一个非常灵活的选项。
我怀疑这个问题与 RequireJS 的不确定性有关,Typeahead 插件的工作与否取决于首先加载的是 jQuery 还是 Knockout。特别是,似乎通过使用 RequireJS 的 shim 使 jQuery 成为 Knockout 的依赖项(即首先加载 jQuery)解决了这个问题:
requirejs.config({
shim: {
knockout: { deps: ['jquery'] },
}
});
这看起来很奇怪,我想更好地了解这里发生的事情以及这是否是问题的合理解决方案 - 即我是否真的在这里解决了潜在问题,或者问题是否会在后续版本的 Knockout 中突然出现或 jQuery。
如果有任何想法,我将不胜感激。
编辑
您可以通过按顺序加载脚本来简单地复制问题,例如:
<script src='knockout.js'></script>
<script src='jquery.js'></script>
这是jsFiddle exhibiting the issue.
按上述顺序插件会失败;否则它将按预期工作。
无论如何,RequireJS 的配置是这样的:
requirejs.config({
baseUrl: "/script",
shim: {
knockout: { deps: ['jquery'] }, # remove this for race condition
}
});
main 的简化版本具有require(['jquery', 'knockout', 'bindings'], ...),其中bindings 定义了敲除处理程序。 bindings.js 文件实际上以 define(['knockout', 'jquery'], ...) 开头。
在这种情况下,虽然问题不是 RequireJS,而是脚本的顺序。
【问题讨论】:
-
您是否将绑定保存在单独的模块中?是什么阻止您访问
define(['ko', 'jq'], function(){ //bindings })?然后在您的视图模型模块中,您将bindings作为依赖项加载。 -
@JonJaques:是的,绑定在一个单独的模块中,这取决于两者。问题似乎不是依赖引起的,而是执行顺序引起的。
-
嗯,你能发布你的视图模型的模块代码吗?不需要整个东西,只是需要的东西,以及您实例化/绑定视图模型的部分?
-
你用这段代码为我节省了几个小时!谢谢!
标签: knockout.js jquery knockout-2.0