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.
source to share
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 .
source to share
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());
source to share