I use select2 and knockoutJs with this simple binding:
ko.bindingHandlers.select2 = {
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var options = ko.toJS(valueAccessor()) || {};
setTimeout(function () {
$(element).select2(options);
}, 0);
}
};
Markup:
<select class="select2" style="width:100%" data-bind="optionsCaption: '',options: $root.items,optionsText: 'description',optionsValue: 'id', value: $root.selectedItem,select2: { placeholder: 'Select an item...',allowClear: true }"></select>
it works! Now I enabled the allowClear
option in Select2 to clear dropdown to a placeholder value like Select an item...
.
If I click the x
icon dropdown properly sets the placeholder but knockout don't update observable binded value!
I think I've to change custombinding adding something like this:
setTimeout(function () {
$(element).select2(options).on("select2-removed", function (e) {
ko.bindingHandlers.value.update(element, function () { return ''; });
});
...
but it won't work!
There are couple of issues.
1) the
update
in bindinghandler is to update DOM based on value change, you should never define anupdate
callback with the ability to mutate your model.The right way is, when define a new bindinghandler, use
init
callback to hook up allchange
events with the model, theupdate
callback is merely a DOM drawing routine.If your
init
provided DOM drawing (such as provided by select2), you don't need to define anupdate
callback.Hence the line
ko.bindingHandlers.value.update(element, function () { return ''; });
only redraw the DOM, it doesn't do what you want.2) the
select2
binding you created has some holes.value
binding doesn't know the existence ofselect2
binding, that's where you struggled.select2
binding has to wait for other binding (theoptions
binding) to finish DOM creation, what's why you usesetTimeout
. But ko provided a way to define sequence of the bindings, just look the source code ofko value
binding, it's defined as'after': ['options', 'foreach']
$root.selectedItem
(a normal select list), the change raised by that UI would not sync back to your select2.The solution
Define
select2
bindingbased on existing(just found out it's not needed), and hook up all change events.value
binding"select2-removed"
event, it's all about"change"
event.select2
provided all drawing, we don't needupdate
callback.shouldIgnore
to break the loop between value subscriber and select2 change event handler.http://jsfiddle.net/huocp/8N3zX/6/http://jsfiddle.net/huocp/8N3zX/9/