2013-07-10 142 views
8

好了Twitter的引导预输入选择,我这个问题,现在争取小时,缩小了问题很简单Fiddle不受KnockoutJS约束

问题是,当我使用Twitter的引导的预输入插件上一个文本输入并进行选择,该值不会在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。

+1

我不是绑定的作者。原始绑定在这里:https://github.com/billpull/knockout-bootstrap我不知道我是否错过了用法中的某些东西? –

回答

4

一种解决方案是,你需要抢在value可观察使用绑定,并使用该函数放慢参数更新它来修改你updater功能:

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

演示JSFiddle.

如果不是绑定的作者比你可以使用updater选项指定updater函数

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

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

演示JSFiddle.

+0

好的,这似乎工作正常。你能解释为什么这与以前的实施相比有效吗?我不是淘汰赛的作者。我想了解原作者在将所有Binding.updater放入更新程序时的想法,以及是否存在使用绑定的“正确”方式。我在HTML中缺少的东西可能是什么?原来的插件是在这里:https://github.com/billpull/knockout-bootstrap –

+0

我不知道这个绑定是在一个库中。我修改了我的答案以使用原始代码。关于作者为何以这种方式设计API,我不知道。我无法在使用'updater'选项的github上找到任何示例。所以我会说这是库中的“API设计错误”,因为我们正在讨论ko-bootstrap库,它应该更习惯于使用KO。所以可以想象这样的正确实现:http://jsfiddle.net/wTRhF/ – nemesv

+0

我认为最初的实现可以很好地用函数而不是简单的值绑定。基本上,updater函数完成它需要处理的选定值,在这里它被分配给ko observable。 nemesv的解决方案是其中的一个捷径。 –

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); 
       }); 
    } 
}; 
3

我宁愿让我的自动完成建议名单从淘汰赛完全分开。我只希望Knockout知道用户实际输入了一个值。

这与用户2576666的技术更接近,因为它使用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