Knockout with Chosen does not set the initial selected options

I am having trouble adjusting initially selected options with Chosen and Knockout 3.3.0.

I've implemented the custom Chosen binding from this question , which works great for selecting items:

ko.bindingHandlers.chosen = {
    init: function (element) {
        ko.bindingHandlers.options.init(element);
        $(element).chosen({ disable_search_threshold: 10 });
    },
    update: function (element, valueAccessor, allBindings) {
        ko.bindingHandlers.options.update(element, valueAccessor, allBindings);
        $(element).trigger('chosen:updated');
    }
};

      

The problem is, if I set the initial value, it won't display it as selected:

<select multiple class="chosen-select" data-bind="chosen: options,
                                        optionsText: 'Label',
                                        optionsValue: 'Id',
                                        selectedOptions: selected">
</select>

      

If I use regex bindings it works correctly:

<select multiple data-bind="options: options,
                                        optionsText: 'Label',
                                        optionsValue: 'Id',
                                        selectedOptions: selected">
</select>

      

I have implemented both as jsFiddle . If you change the self.selected

observableArray () and then run it, you will see that it is reflected in the second <select>

, but nothing is displayed in the first.

+3


source to share


2 answers


You also have to depress the snap selectedOptions

to work correctly chosen

if select

in multiple choice mode.

The problem is that when your observable array selected

changes value selectedOptions

, it correctly sets the selected parameters in the DOM, but does not raise an event 'chosen:updated'

, so the multiselection is chosen

not updated.

One solution would be to create a new chosenSelectedOptions

one that delegates to the original handler and fires the event at update

:

ko.bindingHandlers.chosenSelectedOptions = {
            init: function (element, valueAccessor) {
                ko.bindingHandlers.selectedOptions.init(element, valueAccessor);
            },
            update: function (element, valueAccessor, allBindings) {
                ko.bindingHandlers.selectedOptions.update(element, valueAccessor, allBindings);
                $(element).trigger('chosen:updated');
            }
        };

      



And use this in your binding:

<select multiple class="chosen-select" data-bind="chosen: options,
                                            optionsText: 'Label',
                                            optionsValue: 'Id',
                                            chosenSelectedOptions: selected"></select>

      

Demo JSFiddle .

+6


source


The trick is to evaluate the selected thing after the binding has happened, because the selected one won't initialize correctly without <options>

being in the DOM.

It's a little ugly to use setTimeout, but it works because it delays reloading until the binding is complete.

EDIT: Using a subscription to handle changes to selected options. I find this to be more self-contained than the accepted answer.

** FIDDLE: **



https://jsfiddle.net/brettwgreen/xp1b7cff/

JS:

ko.bindingHandlers.chosen = {
    init: function (element, valueAccessor, allBindings) {
        ko.bindingHandlers.options.init(element, valueAccessor, allBindings);
        var options = ko.unwrap(valueAccessor);
        var el = $(element);
        el.chosen();
        var selectedOptions = allBindings.get('selectedOptions');
        if (ko.isObservable(selectedOptions)) {
            selectedOptions.subscribe(function () {
                setTimeout(function () {
                    el.trigger('chosen:updated');
                }, 10);
            }, null, 'change');
        }
    },
    update: function (element, valueAccessor, allBindings) {
        ko.bindingHandlers.options.update(element, valueAccessor, allBindings);
    }
};

    function viewModel() {

        var self = this;

        self.options = ko.observableArray([{ Id: 1, Label: 'Administrator' }, { Id: 2, Label: 'Moderator' }]);

        self.selected = ko.observableArray([2]);

    }
    ko.applyBindings(new viewModel());

      

0


source







All Articles