Twitter bootstrap typeahead choice not related KnockoutJS

Ok, I spent hours struggling with this problem and narrowing the problem down to a very simple Fiddle

The problem is that when I use the twitter bootstrap typeahead plugin on the text input and make a selection, the value is not updated in the KnockoutJS ViewModel. I know that I could hack it into work, but there must be something that I'm missing here.

I basically have:

knockout binding

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

Knockout ViewModel

 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"/> 

The rest of the material just comes from Twitter Bootstrap.

+8
twitter-bootstrap bootstrap-typeahead
source share
3 answers

One solution is to change your updater function, where you need to capture the observable used in the value binding and update it using the function parameter:

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

JSFiddle demo .

If you are not the author of the binding, you can use the updater parameter to specify the updater function

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

Since updater should return the selected item, the syntax of this is not so good.

JSFiddle demo .

+4
source share

This update material didn't work for me, here's what

 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
source share

I prefer to keep the list of auto-complete suggestions completely separate from the knockout. I want Knockout to find out as soon as the user has actually entered the value.

This is closer to user2576666 because it uses Typeahead user events to force updates in the knockout model when there is a choice or auto-completion. However, it does not require special typeahead bindings and does not require values ​​to be stored in the ViewModel knockout module. This opens up possibilities for a more customizable line termination (for example, using Bloodhound ), which will be uselessly confused if we try to save this in a knockout model. My ViewModel is definitely not suitable for storing autocomplete options for my use case (and, I would suggest, many others, especially if you have a potentially large list that requires a dynamic collection). IMO of this version is also easier to understand:

 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 

Of course, I saved this as a JSFiddle :

+3
source share

All Articles