8

好的,我已经与这个问题斗争了几个小时,并将问题缩小到一个非常简单的Fiddle

问题是,当我在文本输入上使用 twitter bootstrap 的 typeahead 插件并进行选择时,KnockoutJS ViewModel 中的值不会更新。我知道我可以破解它来工作,但一定有一些我在这里遗漏的东西。

基本上我所拥有的是:

淘汰赛绑定

// Bind twitter typeahead
ko.bindingHandlers.typeahead = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var $element = $(element);
        var allBindings = allBindingsAccessor();
        var typeaheadArr = ko.utils.unwrapObservable(valueAccessor());

        $element.attr("autocomplete", "off")
                .typeahead({
                    'source': typeaheadArr,
                    'minLength': allBindings.minLength,
                    'items': allBindings.items,
                    'updater': allBindings.updater
                });
    }
};

淘汰视图模型

function MyModel(){
    var self = this;
    self.productName = ko.observable();
    self.availableProducts = ['One', 'Two', 'Three'];
}

ko.applyBindings(new MyModel());

HTML

<input type="text" data-bind="typeahead:availableProducts, value:productName"/>

其余的东西只是来自 Twitter Bootstrap。

4

3 回答 3

4

我更喜欢将我的自动完成建议列表与 Knockout 完全分开。我只希望 Knockout 知道用户实际输入了一个值。

这更接近于 user2576666 的技术,因为它使用Typeahead 的自定义事件在有选择或自动完成时强制更新 Knockout 模型。但是,它不需要 typeahead 自定义绑定,也不需要将值存储在 Knockout ViewModel 中。这为后续更可定制的补全(例如使用Bloodhound)开辟了空间,如果我们试图将其存储在 Knockout 模型中,这将变得不必要地繁琐。我的 ViewModel 绝对不是为我的用例存储自动完成选项的正确位置(我建议还有许多其他选项——特别是如果您有可能需要动态填充的大型列表)。IMO这个版本也更容易理解:

var availableProducts = ['One', 'Two', 'Three'];

var substringMatcher = function(strs) {
  return function findMatches(q, cb) {
    var matches, substrRegex;
    matches = [];
    substrRegex = new RegExp(q, 'i');
    $.each(strs, function(i, str) {
      if (substrRegex.test(str)) {
        matches.push({ value: str });
      }
    });
    cb(matches);
  };
};


function MyModel(){
    var self = this;
    self.productName = ko.observable();
}

var myModel = new MyModel();

ko.applyBindings(myModel);

var onUpdated = function($e, datum) {
    myModel.productName(datum.value);
};

$(".typeahead")
    .typeahead(
       {hint: true, minLength: 1, highlight: true},
       {displayKey: 'value', source: substringMatcher(availableProducts)})
    .on('typeahead:autocompleted', onUpdated)
    .on('typeahead:selected', onUpdated); // for knockoutJS 

当然,我已将其保存为JSFiddle

于 2014-07-28T05:36:04.210 回答
4

一种解决方案是修改您的updater函数,您需要获取value绑定中使用的 observable 并使用函数参数对其进行更新:

'updater': function(item) {
    allBindings.value(item);
    return item;
}

演示JSFiddle。

如果您不是绑定的作者,那么您可以使用updater选项来指定updater函数

data-bind="typeahead:availableProducts, 
           updater: function(item) { productName(item); return item; }"

因为updater应该返回选定的项目,所以它的语法不是很好。

演示JSFiddle。

于 2013-07-10T08:38:51.353 回答
3

这个更新程序的东西对我不起作用,这是什么

ko.bindingHandlers.typeahead = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var $element = $(element);
        var allBindings = allBindingsAccessor();
        var typeaheadArr = ko.utils.unwrapObservable(valueAccessor());

        var updateValues = function (val) {
            allBindings.value(val);
        };

        $element.attr("autocomplete", "off")
                .typeahead({
                    'local': typeaheadArr,
                    'minLength': allBindings.minLength,
                    'items': allBindings.items,
                }).on('typeahead:selected', function (el, item) {
                    updateValues(item.value);
                }).on('typeahead:autocompleted', function (el, item) {
                    updateValues(item.value);
                });
    }
};
于 2013-10-14T17:44:45.697 回答