Twitter typeahead is a very powerful and easy to use library which can display typeahead on any text box. However if we want to use it with Knockout then ideally we could add a custom binding which handles creation and data queries.
In a project the requirement was to display typeahead using knockout binding which can fetch suggestions from remote web service. The returned data would be in JSON format and it contains text and value fields. I need to display suggestions in the format 'text (value)' but when user selects a suggestion, the corresponding knockout observable should be update with the suggestions value only. e.g. If user selects a suggestion displayed as 'London (LN)' then the observable should store 'LN' only.
After searching online for a while I could find the post below which shows how the latest typeahead can be used to fetch data from a remote web service.
https://stackoverflow.com/questions/35451319/typeahead-change-source
And this google search returns several results for custom knockout typeahead bindings. Combining it all, I finally settled on a custom knockout binding like so:
In a project the requirement was to display typeahead using knockout binding which can fetch suggestions from remote web service. The returned data would be in JSON format and it contains text and value fields. I need to display suggestions in the format 'text (value)' but when user selects a suggestion, the corresponding knockout observable should be update with the suggestions value only. e.g. If user selects a suggestion displayed as 'London (LN)' then the observable should store 'LN' only.
After searching online for a while I could find the post below which shows how the latest typeahead can be used to fetch data from a remote web service.
https://stackoverflow.com/questions/35451319/typeahead-change-source
And this google search returns several results for custom knockout typeahead bindings. Combining it all, I finally settled on a custom knockout binding like so:
//
Bind twitter typeahead
koObject.bindingHandlers.typeahead = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel,
bindingContext) {
var $element = $(element);
var allBindings = allBindingsAccessor();
var url = ko.unwrap(valueAccessor());
var criteria = allBindings.criteria;
var typeaheadOpts = {
name: 'employees',
source: function(query, sync, async)
{
$.ajaxSetup({ timeout:
300000 });
criteria.SearchText =
query;
var data =
JSON.stringify(criteria);
// call ajax to service
$.ajax({
type: "POST", //GET or POST or PUT or DELETE verb
url: url, // locates of the wcf service method
contentType: 'application/json',
crossDomain: true,
data: data,
cache: false,
success: function (data, statusText,
xhr) {
data = data.map(function (item) {
item.textValue =
item.text + " (" + item.value + ")";
return item;
})
async(data);
},
error: function (xhr, status) {
console.log(xhr.error);
console.log(status);
}
});
},
displayKey: 'textValue'
};
if (allBindings.typeaheadOptions) {
$.each(allBindings.typeaheadOptions, function (optionName, optionValue) {
typeaheadOpts[optionName] =
koObject.utils.unwrapObservable(optionValue);
});
}
$element.attr("autocomplete", "off").typeahead({
hint: true,
highlight: true,
minLength: 1
}, typeaheadOpts)
.on('typeahead:selected', function (el, datum) {
console.dir(datum);
allBindings.valueField(datum.value);
});
}
};
This binding can then be used like:
<input type="text" data-bind="valueField: SelectedEmployee, typeahead:
TypeAheadUrl, criteria: Criteria" />
And finally the view model should have properties SelectedEmployee, TypeAheadUrl and Criteria like so:
var ViewModel = function () {
this.Criteria = {Departments: ['FIN', 'HR', 'COM']};
this.TypeAheadUrl = 'https://local.getdata.com';
this.SelectedEmployee = ko.observable('');
};