Knockout Observable CSS Class Binding
HTML
<div data-bind="class: single">Single Observable Class</div>
<div data-bind="class: multiple">Multiple Observable Classes</div>
<button data-bind="click: change">Change</button>
<pre data-bind="text: ko.toJSON($root)"></pre>
CSS
.red {
background: red;
}
.black {
background: black;
}
.blue {
background: blue;
}
.small {
font-size: 12px;
}
.big {
font-size: 20px;
}
JavaScript
//
// Observable CSS Class Binding
//
// See Fiddle for usage: http://jsfiddle.net/kamranayub/3ahUA/
//
ko.bindingHandlers['class'] = {
update: function (element, valueAccessor) {
var currentValue = ko.utils.unwrapObservable(valueAccessor()),
prevValue = element['__ko__previousClassValue__'],
// Handles updating adding/removing classes
addOrRemoveClasses = function (singleValueOrArray, shouldHaveClass) {
if (Object.prototype.toString.call(singleValueOrArray) === '[object Array]') {
ko.utils.arrayForEach(singleValueOrArray, function (cssClass) {
var value = ko.utils.unwrapObservable(cssClass);
ko.utils.toggleDomNodeCssClass(element, value, shouldHaveClass);
});
} else if (singleValueOrArray) {
ko.utils.toggleDomNodeCssClass(element, singleValueOrArray, shouldHaveClass);
}
};
// Remove old value(s) (preserves any existing CSS classes)
addOrRemoveClasses(prevValue, false);
// Set new value(s)
addOrRemoveClasses(currentValue, true);
// Store a copy of the current value
element['__ko__previousClassValue__'] = currentValue.concat();
}
};
//
// Tests
//
var vm = {
single: ko.observable("red"),
multiple: ko.observableArray(["blue","small"])
};
vm.change = function () {
vm.single(vm.single() === "red" ? "black" : "red");
if (vm.multiple.indexOf("small") > -1) {
vm.multiple.remove("small");
vm.multiple.push("big");
} else {
vm.multiple.remove("big");
vm.multiple.push("small");
}
};
ko.applyBindings(vm);