Knock Me Out

Thoughts, ideas, and discussion about Knockout.js

KO 1.3 Preview Part 1: Native Template Engine

| Comments

Update: Knockout 1.3 was eventually renamed to version 2.0

Knockout 1.3 is coming soon! As it has taken shape over the last couple of months, I have been spending quite a bit of time testing against it and am very excited about the changes that it brings. Steve has a nice rundown of the major changes and a link to 1.3 beta.

I wanted to start a series of short posts highlighting some of the things that I have found interesting and useful in 1.3.

The first thing that is very exciting to me is the inclusion of a native template engine. This means that you can use templates within Knockout without referencing the jQuery Templates plugin or even jQuery. This should be a welcome site to developers that are using alternatives to jQuery or simply want to limit the footprint of their app and its dependencies.

By default, the native template engine supports two kinds of templates. First it supports templates that live within a DOM element. This can be within a script tag or even inside an element of any type (of course that element may get rendered and bound itself). The second type of template that it supports is an anonymous template, which uses the content inside of the element as a template. Anonymous templates are used by the native template engine whenever a name is not passed to the template binding.

The if, ifnot, with, and foreach control flow bindings that Steve describes in his post are actually implemented as shortcuts to the template binding and use anonymous templates. I think that it is helpful to understand how the control flow bindings translate to the template binding. Here are some samples:

The if binding will only render/bind the contents of the element when the condition evaluates to a truthy value.

1
2
3
4
5
6
7
8
9
<div data-bind="if: editMode ">
    <input data-bind="value: name" />
</div>

<!-- equivalent to this -->

<div data-bind="template: { if: editMode }">
    <input data-bind="value: name" />
</div>

The ifnot binding will only render/bind the contents when the condition evaluates to a falsy value.

1
2
3
4
5
6
7
8
9
<div data-bind="ifnot: readOnly ">
    <input data-bind="value: name" />
</div>

<!-- equivalent to this -->

<div data-bind="template: { ifnot: readOnly}">
    <input data-bind="value: name" />
</div>

The with binding will do the same as the if binding, but will also switch the context that the template is bound against to whatever is passed to the binding.

1
2
3
4
5
6
7
8
9
<div data-bind="with: selectedItem">
    <input data-bind="value: name" />
</div>

<!-- equivalent to this -->

<div data-bind="template: { if: selectedItem, data: selectedItem }">
    <input data-bind="value: name" />
</div>

The foreach binding will repeat the contents for each item in the array passed to it.

1
2
3
4
5
6
7
8
9
<ul data-bind="foreach: items">
    <li data-bind="text: name"></li>
</ul>

<!-- equivalent to this -->

<ul data-bind="template: { foreach: items }">
    <li data-bind="text: name"></li>
</ul>

One additional note is that the control-flow bindings do force themselves to be rendered by the native template engine by using the templateEngine parameter of the template binding.

The new control flow bindings definitely ease the burden of having to define many small templates in script tags to handle nested content. Implementing these bindings using the template engine is a great way to reuse code and to make sure that dynamic content is all handled in the same manner. Since templates are generally a necessity when dealing with arrays, it is nice that they can be used without any other references than Knockout itself. I believe that these changes will alter the way that we all write even the simplest of Knockout pages.

Next up: defining a custom binding provider.

Comments