Solving Knockout JS calculated bindings Syntax Error

Knockout JS does an excellent job in binding the interface with a View Model. Sometimes you'll need some data manipulation before a value can be shown to the users. How would you go about?

A few options come to mind:

  • Extend the model with a computed property. Technically, it is easy to extend your model, but is it the right thing to do? You are adding a new feature to the model... that might not be the right place to solve your problem. Let's say we want to pretty print a dollar value, is that something you want to add to your model? Or should it be in a different layer?
  • Use a global function to the window. We could add window.printDollar(x){ return '$' + (Math.round(x * 100) / 100); } and use it data-bind="text: window.printDollar(price())". This is a good solution for general tasks that are frequently used. But what if you need to do something that is only needed in the current view?

Using more complex operations might result in the JavaScript exception: Uncaught SyntaxError: Unable to parse bindings.

Printing the position

Let's say we need to list the position of an object in an observable array, with the following rules:

  • First position is 1 ($index + 1).
  • If position is lower than 10, prefix it with a zero.
  • Print a '.' after each position.

First try: wrong way

When I tried to implement this, I used the following - but it did not work:

<span data-bind="text: { 
	var x = $index; 
	x += 1; 
	if(x < 10) x = '0' + x; 
	return x + '.'; 
} "></span>

KnockoutJS doesn't know how to parse this and you'll end up with an error.

Anonymous function to the rescue

The trick is to wrap it into an anonymous function and calling it with the index as a parameter. Because of the nature of this function, we must evaluate the observables that are passed (use () to get the value).

<span data-bind="text: 
	(function(i) { 
		i += 1; 
		if(i < 10) i = '0' + i; 
		return i + '.'; 
	})($index());
">
</span>

This technique is frequently used in JavaScript to achieve information hiding.

  1. Gavin says:

    99% of the time I would use a custom binding for any of this sort of stuff (formatting for display). As a general rule I avoid globals and inline JS in my html templates.

    The other 1% i would use a computed observable but you do raise interesting arguments against doing so.

    Another neat thing with custom bindings is their re-use and portability for future knockout projects.

    1. Kees C. Bakker says:

      That’s a good rule to follow. This is a 0.1% case. Makes me realize we lack a formatting system. Something like .Net’s .ToString with patterns or something. Just for the easy stuff. A String.Format would be even cooler. Something to think about…

expand_less