05 Aug

How to use knockout-bindings to set style of DOM-element

Knockout.js is a very powerful MVVM framework to do some web-application.
I want to explain a trick how you can bind a style of DOM-element in runtime.
The simplest way to use a css-binding is:

<label data-bind="css: 'red'">

so your label will be defined by class ‘red’:

<label class="red">

Another way goes through the binding parameter ‘attr’. You can set all attributes of DOM-element during this parameter directly, but if you want to set the attribute ‘class’ you have to use the name ‘class’ as follows:

<label data-bind="attr: {class: 'red'}">

The binding during ‘css’ attribute adds a class name to an existing list of classes.

<label class="warning" data-bind="css: {red: isDangerous}">

The class ‘red’ will be appended to the class ‘warning’ if the function isDangerous() returns true.
Unlike that, the binding during the parameter ‘class’ overwrites the attribute ‘class’ of an element completely.
Now, imagine the following problem: you will show a collection each element of which has a common class ‘nice’. A loop through the collection will be looked as next example:

<!-- ko: foreach myCollection -->
<label class="nice" data-bind="text: someText"></label>
<!-- /ko -->

Then you want to enable or disable some rows by function isEnabled(). It’s quite easy too:

<label class="nice" data-bind="text: someText, css: {enabled: isEnabled}"></label>

At finally you want set some unique row’s style based on row’s position. You can use something like ‘row’+$index() :

<label class="nice" data-bind="text: someText, css: {enabled: isEnabled, 'row'+$index(): 1}"></label>

But it doesn’t work because Knockout doesn’t understand dynamic names of related parameters!
In such case the parameter ‘class’ helps well. We know that it overwrites the list of classes of DOM-element, because of this we move the description of classes from DOM-element in Knockout binding:

<label data-bind="text: someText, css: {enabled: isEnabled}, attr: {class: 'nice row'+$index()}"></label>

It works and seems good, but you’ll notice soon the class ‘enabled’ will be never set. Why? Because the parameter ‘attr’ will overwrite it.
The solution is very simple: the attribute ‘class’ must always be placed before the parameter ‘css’!

<label data-bind="text: someText, attr: {class: 'nice row'+$index()}, css: {enabled: isEnabled}"></label>

Now it works very well.

Share this

Leave a reply