Knock Me Out

Thoughts, ideas, and discussion about Knockout.js

Dynamically Changing Templates in KnockoutJS

| Comments

An interesting and useful feature that was recently added to KnockoutJS (after 1.12) is the ability to pass a function for the template name to the template binding. This has a few benefits and uses:

  • Allows you to render a section dynamically based on the state of your view model.
  • In a foreach situation allows you to even render individual items in your array with different templates
  • Keeps your templates small and reusable without needing too much conditional logic for rendering each situation

In a simple scenario, you may want a user to be able to toggle between a summary and details mode for viewing a list of articles.

Our view model might look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var viewModel = {
    articles: [{
        id: 1,
        title: "Article One",
        content: "Content for article one."},
    {
        id: 2,
        title: "Article Two",
        content: "Content for article two."},
    {
        id: 3,
        title: "Article Three",
        content: "Content for article three."}
                                               ],
    selectedView: ko.observable("summary"),
    selectedArticle: ko.observable()
};

In our data-binding, we set the selectedView observable based on some radio buttons. The name of the template to use no longer needs to be a string, instead we are able to bind it to the value of selectedView. Note: we return this in an anonymous function, because binding directly to an observable only works currently when we do not pass options as an object literal to the template binding., which we must do to pass foreach or data to the binding.

1
2
3
<input type="radio" name="choices" value="summary" data-bind="checked: selectedView" />Summary
<input type="radio" name="choices" value="details" data-bind="checked: selectedView" />Details
<div data-bind="template: { name: function() { return selectedView(); }, foreach: articles }"></div>

Now, we can easily toggle between summary and details modes. Typically, before we would have used a single template that had conditional logic for each view or used the visible binding to hide one or the other.

This gets a little more interesting when we start changing the template based on factors related to each item in the array. Suppose we also add an edit mode and track an observable for the selected article. Since, our logic is getting more complicated, let’s add a function that we can use to determine the template:

1
2
3
4
viewModel.selectedArticle = ko.observable();
viewModel.templateToUse = function(item) {
    return item === this.selectedArticle() ? edit : this.selectedView();
}.bind(viewModel);

Notice that the function takes in the data item as its first argument. Knockout passes the current item from its foreach loop to the function. Our binding now looks like:

1
<div data-bind="template: { name: templateToUse, foreach: articles }"></div>

Now, the articles are dynamically displayed in summary, details, or edit mode depending on the situation.

Try it out

Comments