I am trying to make jQuery Chosen and KnockoutJS work at the same time.
The problem is "jQuery Chosen" refuses to update options list even though I've created custom binding for it.
Here is the example - http://jsfiddle.net/5fGAf/
I have two changeable selects - "Country" and "Method". "Method" options list depends on country selected. When I select the country for the first time - everything works perfect. But when I want to change the country - "Method" options list remains the same, even though corresponding knockout computed value is updated.
If I manually run $(".chosen-select").trigger('chosen:updated')
in the browser console - options list updates.
Custom binding code:
ko.bindingHandlers.chosen = {
init: function(element) {
$(element).chosen({disable_search_threshold: 10});
},
update: function(element) {
$(".chosen-select").trigger('chosen:updated');
}
};
You have two problems:
- in your fiddle there is no
.chosen-select
so your update
function does not find the select
but anyway you should use $(element)
to access the currently bound element
- in KO 3.0 bindings are fired independently. Because your
chosen
binding is not connected to the your observable array your update
won't fire when you change that array.
You can solve this "update" problem with explicitly declaring a dependency on the options
binding in your custom binding but a better solution would be to delegate to it:
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');
}
};
And use it where you would normally use the options
binding:
<select id="option1" class="form-control"
data-bind="chosen: payoutOptions,
optionsText: 'optionText',
optionsValue: 'optionValue',
value: activePayoutOption"></select>
Demo JSFiddle.
My solution is this:
ko.bindingHandlers.chosen =
{
init: function (element, valueAccessor, allBindings) {
$(element).chosen(valueAccessor());
// trigger chosen:updated event when the bound value or options changes
$.each('value|selectedOptions|options'.split("|"), function (i, e) {
var bv = allBindings.get(e);
if (ko.isObservable(bv))
bv.subscribe(function () { $(element).trigger('chosen:updated'); });
});
},
update: function (element) {
$(element).trigger('chosen:updated');
}
};
You'd use it like so:
<select data-bind="
options: payoutOptions,
optionsText: 'optionText',
optionsValue: 'optionValue',
value: activePayoutOption,
chosen: { disable_search_threshold: 10, width:'100%' }">
</select>
Note that
- The chosen binding is option is added...rather than changing the way the given binding works
- Chosen options (
{ width:'100%',... }
) are not hardwired in the handler
I used a method that is also compatible with all my existing bindings, so I didn't need to go though a ton of html files removing the options
binding.
ko.bindingHandlers.chosen = {
init: function(element, valueAccessor, allBindings) {
$(element).chosen({ disable_search_threshold: 10});
var valueObservable = allBindings.get('value');
var optionsObservable = allBindings.get('options');
var updateList = function() {
$(element).trigger('chosen:updated');
}
if (valueObservable && typeof(valueObservable.subscribe) == 'function') {
valueObservable.subscribe(updateList);
}
if (optionsObservable && typeof(optionsObservable.subscribe) == 'function') {
optionsObservable.subscribe(updateList);
}
$(element).chosen({ disable_search_threshold: 7, width:'100%' });
}
};