farina
farina

Reputation: 3576

KnockoutJS data-bind value on jQueryUI combobox

I'm having a problem binding the jQueryUI combobox value to a computed observable in my KnockoutJS ViewModel. I found a couple of similar questions like "autocomplete-combobox-with-knockout-js-template-jquery" and "knockoutjs-jquery-combobox-binding" but neither resolve my issue.

I think this all resolves from the fact that the jQueryUI combobox doesn't fire a change event when it updates the underlying select.

I made an example here...http://jsfiddle.net/farina/hLfWa/

Upvotes: 2

Views: 5444

Answers (2)

klezer
klezer

Reputation: 11

Fist of all, this was a very good solution from RP Niemeyer. It helped me alot!

However, $("#combobox").next("input") didnt return any elements with me... I also wanted the input to be bound to the changed event of the input. This way, you can type in any text (also empty string) or choose from the combobox and it will always be bound to your preferred knockout observable.

I changed the original solution code to this:

init: function (element, valueAccessor) {
    var observable = valueAccessor();

    //initialize combobox    
    $(element).combobox().ready(function() {
        //when newly create input changes, then update model
        if ($(element).next().find("input") != null && $(element).next().find("input").length > 0) {
            $(element).next().find("input").bind("autocompleteselect", function (event, ui) {
                observable(ui.item ? ui.item.value : "");
            });

            $(element).next().find("input").change(function (event) {
                observable(event ? this.value : "");
            });
        }
    });
},
update: function (element, valueAccessor) {
        //update the element's value, when the model changes
        var value = ko.utils.unwrapObservable(valueAccessor());
        $(element).next().find("input").val(value);
    }

At last i removed the "_removeIfInvalid" function from the "combobox" widget i picked from jquery

Upvotes: 1

RP Niemeyer
RP Niemeyer

Reputation: 114792

The main key is hooking into the select event of the autocomplete widget that is created as part of the combobox.

Something like:

$("#combobox").next("input").bind( "autocompleteselect", function(event, ui) {
    $("#combobox").val(ui.item.value).change();
});

When a value is selected it would change the value of the original select and fire the change event, which is picked up by the value binding.

Even better though would be to use a custom binding that would do this all for you. Something like:

ko.bindingHandlers.combobox = {
    init: function(element, valueAccessor) {
        var observable = valueAccessor();

        //initialize combobox    
        $(element).combobox();

        //when newly create input changes, then update model
        $(element).next("input").bind("autocompleteselect autocompletechange", function(event, ui) {
            observable(ui.item ? ui.item.value : "");
        });


    },
    update: function(element, valueAccessor) {
        //update the element's value, when the model changes
        var value = ko.utils.unwrapObservable(valueAccessor());
        $(element).next("input").val(value);   
    }        
};

Here is a sample: http://jsfiddle.net/rniemeyer/6jWvZ/

The sample includes both a combobox and a normal select, so you can see setting the value from the model (via the second select) or from the combobox.

Upvotes: 8

Related Questions