combine dynamic and static classes through css binding, knockout.js
In knockout.js we can use css binding for static classes
<div data-bind="css: {'translucent ': number() < 10}">static dynamic css classes</div>
and dynamic
<div data-bind="css: color">static dynamic css classes</div>
I've tried http://jsfiddle.net/tT9PK/1/ to combine it in something like
css: {color, translucent: number() < 10}
to get dynamic class color
and static translucent
at the same time, but I get an error. Is there a way to do that?
Solution 1:
You can add dynamic class by css
property and then add static class by attr
property
<div data-bind="attr: { 'class': color }, css: { 'translucent': number() < 10 }">
static dynamic css classes
</div>
Be sure to add any predefined classes to this binding
attr: { 'class': color }
Solution 2:
I solved this problem a while back by just cloning the css
binding as css2
.
ko.bindingHandlers['css2'] = ko.bindingHandlers.css;
Normally you can't use the same binding handler twice in a data-bind attribute, so this allowed me to do the following:
<div data-bind="css: color, css2: { 'translucent': number() < 10 }">static dynamic css classes</div>
I can't quite decide whether I still prefer this, or @Aleksey's answer, but this may be the only choice if you have multiple dynamic classes to add.
Solution 3:
Your best bet is probably not to combine them. Instead use a computed property of your view model to combine them into a single property that you can bind dynamically. That way you can also avoid putting logic in your view with the number() < 10 binding, which is cleaner anyway.
Like this, for example:
viewModel.colorAndTrans = ko.computed(function () {
var cssString = viewModel.color();
if (viewModel.number() < 10) {
cssString += " translucent"
}
return cssString;
});
See this working example: http://jsfiddle.net/tT9PK/4/
Solution 4:
Correct...and to launch you even further, check out this modification.
http://jsfiddle.net/Fv27b/2/
Here, you'll see that not only are we combining the options, but we're creating our own binding entirely...which results in a much more portable extension of not just this view model, but any view model you may have in your project...so you'll only need to write this one once!
ko.bindingHandlers.colorAndTrans = {
update: function(element, valAccessor) {
var valdata = valAccessor();
var cssString = valdata.color();
if (valdata.transValue() < 10) cssString += " translucent";
element.className = cssString;
}
}
To invoke this, you just use it as a new data-bind property and can include as many (or as few) options as possible. Under this specific condition, I might have just provided $data, however if you're wanting a reusable option you need to be more specific as to what data types you need as parameters and not all view models may have the same properties.
data-bind="colorAndTrans: { color: color, transValue: number }"
Hope this does more than answer your question!
Solution 5:
If you really get into complicated styling case, just accumulate all in the computed property. You can do it as Alex mentioned or a bit more readable:
vm.divStyle = ko.computed(function() {
var styles = [];
if (vm.isNested()) styles.push('nested');
if (vm.isTabular()) styles.push('tabular');
else styles.push('non-tabular');
if (vm.color()) styles.push(vm.color());
return styles.join(' ');
});
the main drawback is that you're moving a part of view definition into the viewmodel, that should be more independent. The alternative is to provide all the logic above as a plain js function call, and let knockout evaluate it.