Skip to content

Instantly share code, notes, and snippets.

@jmvtrinidad
Created September 26, 2016 03:56
Show Gist options
  • Save jmvtrinidad/f64f87e923011f225e0e79ef05a4a5ca to your computer and use it in GitHub Desktop.
Save jmvtrinidad/f64f87e923011f225e0e79ef05a4a5ca to your computer and use it in GitHub Desktop.
Boostrap multiselect knockout bindings for objects.
if (typeof ko !== 'undefined' && ko.bindingHandlers && !ko.bindingHandlers.multiselect) {
ko.bindingHandlers.multiselect = {
after: ['options', 'value', 'selectedOptions', 'enable', 'disable'],
preprocess: function (value, name, addBindingCallback) {
var option = eval('(' + value + ')') || {};
if (option.observableKey) {
addBindingCallback('optionsAfterRender', 'function(option, item) { ko.applyBindingsToNode(option, { attr: { "data-key": (item || {})["' +
option.observableKey +
'"] } }, item) }');
}
return value;
},
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var $element = $(element);
var config = ko.toJS(valueAccessor());
$element.multiselect(config);
if (allBindings.has('options')) {
var options = allBindings.get('options');
if (ko.isObservable(options)) {
ko.computed({
read: function () {
options();
setTimeout(function () {
var ms = $element.data('multiselect');
if (ms)
ms.updateOriginalOptions();//Not sure how beneficial this is.
$element.multiselect('rebuild');
}, 1);
},
disposeWhenNodeIsRemoved: element
});
}
}
//value and selectedOptions are two-way, so these will be triggered even by our own actions.
//It needs some way to tell if they are triggered because of us or because of outside change.
//It doesn't loop but it's a waste of processing.
if (allBindings.has('value')) {
var value = allBindings.get('value');
if (ko.isObservable(value)) {
ko.computed({
read: function () {
value();
setTimeout(function () {
$element.multiselect('refresh');
}, 1);
},
disposeWhenNodeIsRemoved: element
}).extend({ rateLimit: 100, notifyWhenChangesStop: true });
}
}
//Switched from arrayChange subscription to general subscription using 'refresh'.
//Not sure performance is any better using 'select' and 'deselect'.
if (allBindings.has('selectedOptions')) {
var selectedOptions = allBindings.get('selectedOptions');
if (ko.isObservable(selectedOptions)) {
ko.computed({
read: function () {
// Added to handle knockout binding to an object...not just a value
// multiselect needs the selected property on the options, else it wont show them on refresh
if ((config.optionsKey !== undefined) &&
(config.optionsKey !== null) &&
(config.optionsKey.length > 0) &&
(config.observableKey !== undefined) &&
(config.observableKey !== null) &&
(config.observableKey.length > 0)) {
var observableKey = config.observableKey;
var selectedValues = selectedOptions()
.map(function(selectedOption) {
return ko.isObservable(selectedOption[observableKey])
? selectedOption[observableKey]()
: selectedOption[observableKey];
});
setTimeout(function () {
$element.multiselect('rebuild');
}, 1);
if (selectedValues.length) {
setTimeout(function () {
$element.multiselect('select', selectedValues);
}, 1);
}
}
},
disposeWhenNodeIsRemoved: element
}).extend({ rateLimit: 100, notifyWhenChangesStop: true });
}
}
var setEnabled = function (enable) {
setTimeout(function () {
if (enable)
$element.multiselect('enable');
else
$element.multiselect('disable');
});
};
if (allBindings.has('enable')) {
var enable = allBindings.get('enable');
if (ko.isObservable(enable)) {
ko.computed({
read: function () {
setEnabled(enable());
},
disposeWhenNodeIsRemoved: element
}).extend({ rateLimit: 100, notifyWhenChangesStop: true });
} else {
setEnabled(enable);
}
}
if (allBindings.has('disable')) {
var disable = allBindings.get('disable');
if (ko.isObservable(disable)) {
ko.computed({
read: function () {
setEnabled(!disable());
},
disposeWhenNodeIsRemoved: element
}).extend({ rateLimit: 100, notifyWhenChangesStop: true });
} else {
setEnabled(!disable);
}
}
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$element.multiselect('destroy');
});
},
update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var $element = $(element);
var config = ko.toJS(valueAccessor());
$element.multiselect('setOptions', config);
$element.multiselect('rebuild');
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment