【问题标题】:Twitter Bootstrap typeahead selection not bound by KnockoutJSTwitter Bootstrap 预输入选择不受 KnockoutJS 的约束
【发布时间】:2013-07-08 01:47:09
【问题描述】:

好的,我已经与这个问题斗争了几个小时,并将问题缩小到一个非常简单的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。

【问题讨论】:

标签: twitter-bootstrap knockout.js bootstrap-typeahead


【解决方案1】:

一种解决方案是修改您的 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.

【讨论】:

  • 好的,这似乎工作正常。你能解释一下为什么这与以前的实现相比有效吗?我不是淘汰赛绑定的作者。我想了解原作者将 allBindings.updater 放入更新程序时的想法,以及是否有使用绑定的“正确”方式。我可能在 HTML 中遗漏了什么?原插件在这里:github.com/billpull/knockout-bootstrap
  • 我不知道这个绑定在库中。我修改了我的答案以使用原始代码。关于作者为什么以这种方式设计API我不知道。我无法在 github 上找到任何使用 updater 选项的示例。所以我会说这是库中的一个“API 设计错误”,因为我们正在讨论 ko-bootstrap 库,它应该更惯用地使用 KO。所以可以想象这样的事情是正确的实现:jsfiddle.net/wTRhF
  • 我认为最初的实现适用于函数而不是简单的值绑定。基本上 updater 函数对选定的值做了它需要做的事情,这里它分配给一个 ko observable。 nemesv 的解决方案是一个捷径。
  • 太棒了!现在我知道了!我真的很喜欢真正理解为什么事情不工作,而不是让他们工作。但是,我不喜欢函数的想法。假设我需要想办法让这个绑定更自动地工作。
【解决方案2】:

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

这更接近于 user2576666 的技术,因为它使用Typeahead's custom events 在有选择或自动完成时强制更新 Knockout 模型。但是,它不需要预先输入的自定义绑定,也不需要将值存储在 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 

当然,我已将其保存为a JSFiddle

【讨论】:

    【解决方案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-11-18
      • 1970-01-01
      • 2013-06-15
      • 2012-03-04
      • 2014-10-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-22
      • 1970-01-01
      相关资源
      最近更新 更多