简单的Knockout + Bootstrap Typeahead插件竞争条件

时间:2013-02-05 23:28:37

标签: knockout.js jquery knockout-2.0

我有一个very simple Bootstrap Typeahead binding (jsFiddle)的Knockout.js,像这样:

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> element将显示所选文本(“Alpha”),但绑定的observable将为“alp”。

在当前系统中,Typeahead绑定不能直接修改给定的observable,因此传递{ source: src, observable: item }无法解决问题。此Typeahead绑定的作用仅是更新绑定输入区域的内容。

我已尝试从绑定中触发相关事件,例如'keydown','keypress'和'keyup',但由于显而易见的原因,这不是一个非常有弹性的选项。

我怀疑问题与RequireJS的不确定性有关,Typeahead插件的工作与否取决于jQuery或Knockout是否先加载。特别是,似乎通过使jQuery成为Knockout的依赖项(即首先加载jQuery)和RequireJS的shim来解决这个问题:

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定义了Knockout处理程序。 bindings.js文件实际上以define(['knockout', 'jquery'], ...)开头。

在这种情况下虽然问题不是RequireJS,而是脚本的排序。

1 个答案:

答案 0 :(得分:0)

我怀疑你在某种程度上错过了依赖。可能是引导程序。

请看我的例子。你是正确的看看垫片配置。 http://jsfiddle.net/jaquers/sfvy9/2/

requirejs.config({
    shim: {
        'bootstrap': {
            deps: ['jquery'],
            exports: 'jQuery.fn.typeahead'  // we can't test for more than one object                   
        }
    }
});