Knockout - Extender
Simple checkbox and radio controls with extends to format input and output
by Ben Clayton
HTML
<script src="//knockoutjs.com/downloads/knockout-2.2.1.js"></script>
<script src="http://knockoutjs.com/downloads/knockout-3.2.0.js"></script>
Checkbox:
<input type="checkbox" data-bind="checked: mychk; css: mkchk.myinvalid() "></input>
<br/>
<br/> gender: Male:
<input type="radio" name="gender" data-bind="checked: mygender" value="M"></input>
Female:
<input type="radio" name="gender" data-bind="checked: mygender" value="F"></input>
CSS
body {
padding: 10px;
}
input.myinvalid {
background-color:red;
}
JavaScript
//=====================================================================================================================
// knockout extenders for observables
// register an extender class to handle adding classes to elements 'invalid' or 'dirty'
// These observables have a css binding to the elements
// ex. of set 'myinvalid' class vm_1.travel.setInvalid(true)
ko.extenders.controlclass = function(target,linked_parent) {
//add some sub-observables to our observable
target.dirty = ko.observable(false);
target.myinvalid = ko.observable(false);
target.setInvalid=function(v){ // public method
if(typeof(v) != 'boolean') v=true; // default to true if parameter no given
this.myinvalid(v);
}
function setDirty(val){ // private method, parameter if used will be the value of form element
target.dirty(true);
target.myinvalid(false); // clear any invalid class which migh have been added by validation on form submit
if(linked_parent){ // clear parent observable(if there is one) which is normally a div wrapping all checkboxes in a set
linked_parent( (linked_parent()?linked_parent():0) + (val?1:-1) );// keep qty selected on parent
//console.log('linked_parent '+ linked_parent());
linked_parent.myinvalid(false);
}
}
// set dirty class on any change on element value
target.subscribe(setDirty);
//return the original observable
return target;
};
ko.extenders.checkbox = function(target, spare) {
//create a writable computed observable to intercept writes to our observable
// original observable value is a boolean for a checkbox
// so input and output need processing to work with 0/1 instead
// also tolerate many other possible ways of saying true
var result = ko.pureComputed({
read: function() {
return target() ? 1 : 0
}, //return the original observables value but processed into how we want the value to be available to storage.
write: function(newValue) {
var current = target();
newValue =...