Search code examples
javascriptknockout.jstypeahead.jscustom-binding

Update Value In textbox using Knockout + Typeahead Custom Binding


I am making an application using knockout + typeahead that will show suggestion list of entered character matches the list.

All thing working fine. Only problem is when I select the item from list it stores the whole object.

I want to store only name is first textbox and as per it store related value in second textbox.

I am not getting how to do that ?

can do using subscribe ? put subscribe on first textbox, it will get whole object then it will process the object then store values in related textbox.

HTML :

<input type="text" class="form-control" data-bind="typeahead: data, dataSource: categories"/> *
<input type="text" class="form-control" data-bind="value: item"/>

Java Script :

var ViewModel = function () {
    var self = this;

    self.categories = [
           { name: 'Fruit', items: 'abc' },
            { name: 'Vegetables', items: 'xyz' }
        ];
    self.data = ko.observable();
    self.item = ko.observable();
};
var viewModel = new ViewModel();

ko.bindingHandlers.typeahead = {
    init: function (element, valueAccessor, allBindingsAccessor) {

        var $e = $(element);
        var accessor = valueAccessor();
        var source = allBindingsAccessor().dataSource || [];

        var names = new Bloodhound({
            datumTokenizer: function (d) {
                return Bloodhound.tokenizers.whitespace(d.name);
            },
            queryTokenizer: Bloodhound.tokenizers.whitespace,
            local: source
        });
        names.initialize();
        var substringMatcher = function() {
            return function findMatches(q, cb) {
                var matches, substrRegex;
                substrRegex = new RegExp(q, 'i');
                $.each(source, function(i, p) {
                    if (substrRegex.test(p.name)) {
                        matches.push({ value: p });
                    }
                });
                console.dir(matches);
                cb(matches);
            };
        };
        $e.typeahead({
                hint: true,
                highlight: true,
                minLength: 1
            },
            {
                name: 'name',
                displayKey: 'name',
                source: names.ttAdapter()
            }).on('typeahead:selected', function (el, datum) {
                console.dir(datum);
                accessor(datum);
            }).on('typeahead:autocompleted', function (el, datum) {
                console.dir(datum);
                console.log(accessor);
            });
    },
    update: function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        console.log(value);
        $(element).val(ko.utils.unwrapObservable(valueAccessor()));
    }
};
ko.applyBindings(viewModel);

Here is jsfiddle of it.

I have asked question in morning also but i don't get answer so I code myself by studying the tutorials, but now I am stuck Here.

Any Suggestion on this situation ??


Solution

  • There are certain limitations with the temporary workout like knockout extension for Bootstrap Typeahead. I used it before in my project but it lead to a lot of limitations like custom control over templating, custom control over selected object property and selected object value. So I moved on to plugin jqAuto which is based on JQuery-UI autocomplete.

    This plugin has enormous range of customizations and is faster than typeahead. I replicated your code in the jqAuto code and it is faster and cleaner than bootstrap typeahead.

    JavaScript

    var ViewModel = function() {    
        self.categories = [
               { name: 'Fruit', items: 'abc' },
                { name: 'Vegetables', items: 'xyz' }
            ];
    
        self.data = ko.observable("");
        self.item = ko.observable();
    
    };
    
    ko.applyBindings(new ViewModel());
    

    HTML

    <input data-bind="jqAuto: { source: categories, value: data, dataValue : data, inputProp: 'name', valueProp: 'name', labelProp: 'name'  }" />  
    

    You can control the label propery, input property as well as value property in granular level.

    Fiddle demo : http://jsfiddle.net/rahulrulez/uGGb8/4/

    Detailed documentation of jqAuto plugin is given here : https://github.com/rniemeyer/knockout-jqAutocomplete