Knock Me Out

Thoughts, ideas, and discussion about Knockout.js

Quick Tip: Reusing a Template by Passing Options in KnockoutJS

| Comments

Have you ever had the need to pass extra parameters to a template in addition to your data, so that you are able to reuse a single template for a variety of situations? Maybe you need to do some filtering, additional styling, or want to vary some of the text. Without passing this information to your template, you might have to create a number of very similar templates, bloated templates that include lots of branching, or pollute your data with information that is often only related to the UI.

The jQuery Templates plugin does support passing an options map to the .tmpl function. Current KnockoutJS code (after 1.12), now has the ability to pass the options map in the template binding using a templateOptions field.

The basic syntax looks like:

1
<div data-bind=“template: { name: items’, data: newItems, templateOptions: { header: New Items!”} }”></div>

In this example, you would then access the option using $item.header in your template code.

Sample

Suppose that your model contains menu items for breakfast, lunch, and dinner. You would like to render a section for each of these types of menu items, but use slightly different styles and header/footer information.

Let’s say our view model looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var viewModel = {
    breakfast: [
        {name: toast, price: 2.50},
        {name: pancakes, price: 4.00},
        {name: eggs, price: 3.25}],
    lunch: [
        {name: grilled cheese, price: 4.00},
        {name: hot dog, price: 3.50},
        {name: pizza, price: 6.00}],
    dinner: [
        {name: steak, price: 15.75},
        {name: fish, price: 11.00},
        {name: salad, price: 8.25}
    ],
};

ko.applyBindings(viewModel);

Along with showing the name and price of each item, we would like to have a custom header, footer, and apply some different styling to each section.

By passing templateOptions, we can have a single template that is able to render the different types of menu items.

1
2
3
<div data-bind=“template: { name: items’, data: breakfast, templateOptions: { header: Breakfast Items’, message: Wake up to these delicious items!’, class: breakfast } }”></div>
<div data-bind=“template: { name: items’, data: lunch, templateOptions: { header: Lunch Dishes’, message: Stop by for a quick lunch!’, class: lunch } }”></div>
<div data-bind=“template: { name: items’, data: dinner, templateOptions: { header: Dinner Entrees’, message: Enjoy our tasty dinner selections!’, class: dinner } }”></div>

Our template can then loop through our items and access the additional options that we passed to it. In this example, I am assuming that the items are not changing, so we are not using observables, using foreach on the template binding, or even setting up indvidual bindings in the template.

1
2
3
4
5
6
7
8
9
10
11
12
13
<script id=“items” type=“text/html”>
    <h3>${$item.header}</h3>
    <div class=${$item.class}>
        {{each $data}}
        <p>
            <span class=name>${name}</span>
            <span class=price>${price.toFixed(2)}</span>
        </p>
        {{/each}}
    </div>
    <p><em>${$item.message}</em></p>
    <hr />
</script>

The end result is a single, versatile template for displaying our items.

Warning

If you are passing templateOptions to the template binding from a nested template (so, specifying a template binding from within a template), then pay special attention to your syntax. You will encounter a problem, if your binding looks like this:

1
<div data-bind=“template: { name: items’, data: newItems, templateOptions: { header: New Items!”}}”></div>

The jQuery Templates plugin gets confused by the }} at the end of your binding, since that is part of its syntax. Adding a space between your braces will work fine. Hopefully this prevents someone from a little unnecessary frustration.

1
<div data-bind=“template: { name: items’, data: newItems, templateOptions: { header: New Items!”} }”></div>

Try it out here

Comments