Skip to content

Instantly share code, notes, and snippets.

Created December 31, 2012 09:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save anonymous/4418571 to your computer and use it in GitHub Desktop.
Save anonymous/4418571 to your computer and use it in GitHub Desktop.
A smarter `checked` binding and `value` binding, so you can bind the checked property of a checkbox to an array of model property values, rather than a string array.
var oldValueBinding = ko.bindingHandlers['value'];
ko.bindingHandlers['value'] = {
'init': function (element, valueAccessor, allBindingsAccessor) {
// If `checked` binding is present, ignore this binding because
// user wishes to bind the checked value to the model value
var allBindings = allBindingsAccessor(),
hasChecked = allBindings.hasOwnProperty("checked");
if (hasChecked) {
return;
}
oldValueBinding['init'].apply(this, arguments);
},
'update': function (element, valueAccessor, allBindingsAccessor) {
// If `checked` binding is present, ignore this binding because
// user wishes to bind the checked value to the model value
var allBindings = allBindingsAccessor(),
hasChecked = allBindings.hasOwnProperty("checked");
if (hasChecked) {
return;
}
oldValueBinding['update'].apply(this, arguments);
}
};
ko.bindingHandlers['checked'] = {
'init': function (element, valueAccessor, allBindingsAccessor) {
var updateHandler = function() {
var valueToWrite;
if (element.type == "checkbox") {
valueToWrite = element.checked;
} else if ((element.type == "radio") && (element.checked)) {
valueToWrite = element.value;
} else {
return; // "checked" binding only responds to checkboxes and selected radio buttons
}
var modelValue = valueAccessor(), unwrappedValue = ko.utils.unwrapObservable(modelValue),
allBindingsValue = allBindingsAccessor();
if ((element.type == "checkbox") && (unwrappedValue instanceof Array)) {
// For checkboxes bound to an array, we add/remove the checkbox value to that array
// This works for both observable and non-observable arrays
var boundValue = (allBindingsValue.hasOwnProperty("value") && ko.utils.unwrapObservable(allBindingsValue.value)) || element.value;
var existingEntryIndex = ko.utils.arrayIndexOf(unwrappedValue, boundValue);
if (element.checked && (existingEntryIndex < 0))
modelValue.push(boundValue);
else if ((!element.checked) && (existingEntryIndex >= 0))
modelValue.splice(existingEntryIndex, 1);
} else {
ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'checked', valueToWrite, true);
}
};
ko.utils.registerEventHandler(element, "click", updateHandler);
// IE 6 won't allow radio buttons to be selected unless they have a name
if ((element.type == "radio") && !element.name)
ko.bindingHandlers['uniqueName']['init'](element, function() { return true });
},
'update': function (element, valueAccessor, allBindingsAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor()),
allBindingsValue = allBindingsAccessor();
if (element.type == "checkbox") {
if (value instanceof Array) {
var boundValue = (allBindingsValue.hasOwnProperty("value") && ko.utils.unwrapObservable(allBindingsValue.value)) || element.value;
// When bound to an array, the checkbox being checked represents its value being present in that array
element.checked = ko.utils.arrayIndexOf(value, boundValue) >= 0;
} else {
// When bound to anything other value (not an array), the checkbox being checked represents the value being trueish
element.checked = value;
}
} else if (element.type == "radio") {
element.checked = (element.value == value);
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment