Commit db4d64e9 authored by Aaron-P's avatar Aaron-P

Improved knockout binding

Improves the initialization of the multiselect by waiting for other select related bindings to finish first.
Moved the subscription to other binder events to init so they aren't re-executed all the time.
Added support for value binding.
Added support for observable configuration properties.
Observable subscription rate-limited (by @IDisposable).
Simplified how selection changes are processed (simpler code, not sure about performance).
parent 847873e4
...@@ -11,71 +11,67 @@ ...@@ -11,71 +11,67 @@
if (typeof ko !== 'undefined' && ko.bindingHandlers && !ko.bindingHandlers.multiselect) { if (typeof ko !== 'undefined' && ko.bindingHandlers && !ko.bindingHandlers.multiselect) {
ko.bindingHandlers.multiselect = { ko.bindingHandlers.multiselect = {
after: ['options', 'value', 'selectedOptions'],
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var $element = $(element);
var listOfSelectedItems = allBindingsAccessor().selectedOptions; var config = ko.toJS(valueAccessor());
var config = ko.utils.unwrapObservable(valueAccessor());
$element.multiselect(config);
$(element).multiselect(config);
var options = allBindings.get('options');
if (isObservableArray(listOfSelectedItems)) { if (ko.isObservable(options)) {
ko.computed(function () {
// Set the initial selection state on the multiselect list. options();
$(element).multiselect('select', ko.utils.unwrapObservable(listOfSelectedItems)); setTimeout(function () {
var ms = $element.data('multiselect');
// Subscribe to the selectedOptions: ko.observableArray if (ms)
listOfSelectedItems.subscribe(function (changes) { ms.updateOriginalOptions();//Not sure how beneficial this is.
var addedArray = [], deletedArray = []; $element.multiselect('rebuild');
forEach(changes, function (change) { }, 1);
switch (change.status) {
case 'added':
addedArray.push(change.value);
break;
case 'deleted':
deletedArray.push(change.value);
break;
}
}); });
if (addedArray.length > 0) {
$(element).multiselect('select', addedArray);
} }
if (deletedArray.length > 0) { //value and selectedOptions are two-way, so these will be triggered even by our own actions.
$(element).multiselect('deselect', deletedArray); //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.
}, null, "arrayChange"); var value = allBindings.get('value');
} if (ko.isObservable(value)) {
ko.computed(function () {
value();
setTimeout(function () {
$element.multiselect('refresh');
}, 1);
}).extend( { rateLimit: 100, notifyWhenChangesStop: true });
}
//Switched from arrayChange subscription to general subscription using 'refresh'.
//Not sure performance is any better using 'select' and 'deselect'.
var selectedOptions = allBindings.get('selectedOptions');
if (ko.isObservable(selectedOptions)) {
ko.computed(function () {
selectedOptions();
setTimeout(function () {
$element.multiselect('refresh');
}, 1);
}).extend({ rateLimit: 100, notifyWhenChangesStop: true });
}
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$element.multiselect('destroy');
});
}, },
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var $element = $(element);
var listOfItems = allBindingsAccessor().options, var config = ko.toJS(valueAccessor());
ms = $(element).data('multiselect'),
config = ko.utils.unwrapObservable(valueAccessor());
if (isObservableArray(listOfItems)) {
// Subscribe to the options: ko.observableArray incase it changes later
listOfItems.subscribe(function (theArray) {
$(element).multiselect('rebuild');
});
}
if (!ms) { $element.multiselect('setOptions', config);
$(element).multiselect(config); $element.multiselect('rebuild');
}
else {
ms.updateOriginalOptions();
}
} }
}; };
} }
function isObservableArray(obj) {
return ko.isObservable(obj) && !(obj.destroyAll === undefined);
}
function forEach(array, callback) { function forEach(array, callback) {
for (var index = 0; index < array.length; ++index) { for (var index = 0; index < array.length; ++index) {
callback(array[index]); callback(array[index]);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment