Knockout Part 5: Templates

In the past examples, we created a view like:

<div data-bind=”foreach:people”>
<div data-bind=”html:name”></div>
</div>

Where the model was:

function viewModel() {
var self = this;

self.people = ko.observableArray([{ name: “ABC” }]);
}

And this binding works fine; but there is another way to do this.  We can also use templates, or a section of markup

<!– name matches the ID of the template, data matches the data property –>
<div data-bind=”template: { name: ‘peopleScript’, data: itemData }”> </div>

<!– id is required –>
<script id=”peopleScript” type=”text/html”>
<ul data-bind=”foreach: $data”>
<li>
Name: <span data-bind=”text: name”> </span>
State: <span data-bind=”{ text: state }”> </span>

<span data-bind=”visible: ($root.inState($data))”>
(In State)
<span>
</li>
</ul>
</script>

Instead of using the typical bindings, we define an element with a template binding.  The template binding needs a name, matching an existing template name, and a reference to an observable property (itemData is defined in the view model).  Next, we have the template itself; the template is a script tag with the “text/html” designation.  This is the designation Knockout came up with for its templates.  A template uses a script tag, defines a markup segment with appropriate bindings directed to the context of the data.  This means the template represents the itemData observable.  This is why I use the $data reference in the foreach binding, referring to the itemData array of objects.

There are some pros and cons to this approach; here we have an isolated template not mixed in with the rest of the markup; this allows some separation, which in some cases is good and some bad.  It may actually be possible to load or create a template on the fly, and not be dependent on a static template (I have not actually tried this to verify it).  A template is bound to the context of the data bound to it, which can be a single object or an array.

The creation of the model is more complex in this example.  Take a look at the sample below:

$(document).ready(function() {

$.ajax({
url: “jsondata.js”,
type: “get”,
dataType: “json”,
success: function(data) {
function viewDataModel() {
var self = this;

self.itemData = [];

//translate JSON objects into observables
for (var i = 0, len = data.people.length; i < len; i++) {
self.itemData.push({ name: ko.observable(data.people[i].name), state: ko.observable(data.people[i].state) });
}

self.inState = function(person) {
var state = person.state();
if (state != null && state == “PA”)
return true;
else
return false;
}
};

ko.applyBindings(new viewDataModel());
},
error: function(ex) {
. .
}
});

});

This sample builds the view model after retrieving the data from the server; since it’s a one-time binding, this works OK.  It would be more preferrable to create the view with empty values and bind it, followed by setting the individual property values with the results of the AJAX call.

I hope this post illustrated how we can use templates in a fashion that make it easier to bind snippets of markup.