Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using select2.js with multiple select optgroup and knockoutJS

I am trying to achieve a databinding for multiple selection with optgroup using knockoutJS. In addition we would like to use select2 for its search and display capabilities.

Here is the fiddle sample.

Everything works well when the items are added directly using the html control. You may pickup some countries in the example above and click the view button to see that the code of the countries are well retrieved. However, I would like to populate the items another way. Precisely, I created a command to flush the observable array containing the selected items and force the first item in the list of available options to be selected (which is the country Laos in our example). This command is executed when clicking the second button.

After clicking this latter button, you can check that the observable selectedCountries contains the expected values by clicking the first button. Unfortunately, the UI control is not refreshed, do you have an idea how to do that? The html databiding for my view looks like

<select class="multi-select" data-bind="foreach: availableCountries,selectedOptions:selectedCountries" multiple="multiple">
    <optgroup data-bind="attr: {label: label}, foreach: children">
        <option data-bind="text: display, value: code"></option>
    </optgroup>
</select>
like image 980
Benoit Patra Avatar asked Dec 02 '25 02:12

Benoit Patra


1 Answers

The short answer is that Select2 doesn't know about changes you make to the underlying model.

I was able to make your sample work using a hack, see here: http://jsfiddle.net/bXPM6/

The changes made are:

<select id="foo" class="multi-select" data-bind="foreach: availableCountries, selectedOptions:selectedCountries" multiple="multiple">

(Note the added id=foo).

And I added a subscription to the observable:

function MyViewModel(){
    var self = this;
    self.availableCountries = ko.observableArray(app.availableCountries());
    self.selectedCountries = ko.observableArray([]);

    // added this bit
    self.selectedCountries.subscribe(function (newValue) {
        $('#foo').select2("val", newValue);
    });
}

The better option is to make a custom knockout binding that can keep Select2 updated with changes to your model.

Something like this:

HTML:

<select class="multi-select" data-bind="foreach: availableCountries, selectedOptions:selectedCountries, select2: selectedCountries" multiple="multiple">

JavaScript:

ko.bindingHandlers.select2 = {
    update: function (element, valueAccessor) {
        $(element).select2("val", ko.unwrap(valueAccessor()) || "");
    }
};

Hope this is of some help.

like image 193
Paul Avatar answered Dec 03 '25 16:12

Paul