$('.buttonSetTest').buttonset();
$('#cbStyled').button();
ko.bindingHandlers['buttonset'] = {
'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();
if ((element.type == "checkbox") && (ko.utils.unwrapObservable(modelValue) 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 existingEntryIndex = ko.utils.arrayIndexOf(ko.utils.unwrapObservable(modelValue), element.value);
if (element.checked && (existingEntryIndex < 0)) modelValue.push(element.value);
else if ((!element.checked) && (existingEntryIndex >= 0)) modelValue.splice(existingEntryIndex, 1);
} else if (ko.isWriteableObservable(modelValue)) {
if (modelValue() !== valueToWrite) { // Suppress repeated events when there's nothing new to notify (some browsers raise them)
modelValue(valueToWrite);
}
} else {
var allBindings = allBindingsAccessor();
if (allBindings['_ko_property_writers'] && allBindings['_ko_property_writers']['checked']) {
allBindings['_ko_property_writers']['checked'](valueToWrite);
}
}
};
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) {
/////////////// addded code to ko checked binding /////////////////
var buttonSet = function(element) {
// now update the css classes
// Normally when knockout updates button, there
// isn't an event to transfer new status
// to buttonset label
var buttonId = $(element).attr('id');
if (buttonId) {
var buttonSetDiv = $(element).parent('.ui-buttonset');
var elementLabel = $(buttonSetDiv).find('label[for="' + buttonId + '"]');
if (elementLabel.length === 0) {
// was just a single button, so look for label
elementLabel = $(element).parent('*').find('label[for="' + buttonId + '"]');
}
// check to see if element is already configured
if (element.checked && !$(elementLabel).hasClass('ui-state-active')) {
$(elementLabel).addClass('ui-state-active');
}
if (!element.checked && $(elementLabel).hasClass('ui-state-active')) {
$(elementLabel).removeClass('ui-state-active');
}
}
};
/////////////// end add ///////////////////////////
var value = ko.utils.unwrapObservable(valueAccessor());
if (element.type == "checkbox") {
if (value instanceof Array) {
// When bound to an array, the checkbox being checked represents its value being present in that array
element.checked = ko.utils.arrayIndexOf(value, element.value) >= 0;
} else {
// When bound to anything other value (not an array), the checkbox being checked represents the value being trueish
element.checked = value;
}
/////////////// addded code to ko checked binding /////////////////
buttonSet(element);
/////////////// end add ///////////////////////////
// Workaround for IE 6 bug - it fails to apply checked state to dynamically-created checkboxes if you merely say "element.checked = true"
if (value && ko.utils.isIe6) element.mergeAttributes(document.createElement("<input type='checkbox' checked='checked' />"), false);
} else if (element.type == "radio") {
element.checked = (element.value == value);
/////////////// addded code to ko checked binding /////////////////
buttonSet(element);
/////////////// end add ///////////////////////////
// Workaround for IE 6/7 bug - it fails to apply checked state to dynamically-created radio buttons if you merely say "element.checked = true"
if ((element.value == value) && (ko.utils.isIe6 || ko.utils.isIe7)) element.mergeAttributes(document.createElement("<input type='radio' checked='checked' />"), false);
}
}
};
var viewModel = {
radio: ko.observable('M'),
cb: ko.observable('true')
};
ko.applyBindings(viewModel);
<form>
<p>Using "checked" binding</p>
<div class="buttonSetTest">
<input type="radio" id="radio1a" name="radioChk" value='y' data-bind='checked: radio'/>
<label for="radio1a">Yes</label>
<input type="radio" id="radio2a" name="radioChk" checked="checked" value='n' data-bind='checked: radio'/>
<label for="radio2a">No</label>
<input type="radio" id="radio3a" name="radioChk" value='M' data-bind='checked: radio'/>
<label for="radio3a">Maybe</label>
</div>
<p>Using "buttonset" binding</p>
<div class="buttonSetTest">
<input type="radio" id="radio1" name="radio" value='y' data-bind='buttonset: radio'/>
<label for="radio1">Yes</label>
<input type="radio" id="radio2" name="radio" checked="checked" value='n' data-bind='buttonset: radio'/>
<label for="radio2">No</label>
<input type="radio" id="radio3" name="radio" value='M' data-bind='buttonset: radio'/><label for="radio3">Maybe</label>
</div>
<p>Let's try normal buttons bound to same value</p>
<div id="normalButtons">
<input type="radio" id="normalRb1" name="radio1" value='y' data-bind='checked: radio'/><label for="normalRb1">Yes</label>
<input type="radio" id="normalRb2" name="radio1" checked="checked" value='n' data-bind='checked: radio'/>
<label for="normalRb2">No</label>
<input type="radio" id="normalRb3" name="radio1" value='M' data-bind='checked: radio' />
<label for="normalRb3">Maybe</label>
</div>
<p> Current Radiobutton Value = <span data-bind='text: radio' ></span></p>
<p>Do checkboxes</p>
<p><input type='checkbox' id='cbStyled' name='cbStyled' data-bind='buttonset: cb'><label for='cbStyled' data-bind>Styled Cb </label></p>
<p> <input type='checkbox' id='cbUnStyled' name='cbUnStyled' data-bind='checked: cb'><label for='cbUnStyled' data-bind>Normal CB Binding</label></p>
</form>
p{padding: 5px}
External resources loaded into this fiddle: