You can use template feature in Knockoutjs to render your data. Templates are a straight forward way to build complex UI structure, often with repeating or nested blocks. You can use templates to show repeating data, such as data in tables or portfolios.
From the point of view of Object JavaScript, templates help you further separate out the code that gets and sets the data, from the code that renders the data. Templates provide you a way to reuse similar views throughout your application. And they help you isolate the view that deals with data in a way that you can find and understand in your own code.
Templates as they are used in this post, are reusable chunks of HTML that relate to your observables in Knockout.
There are two main ways of using templates:
- Native templating where you use foreach, if, with and other control bindings. The control flow bindings use the HTML markup in your element and render against your data. The feature is built into Knockout.
- String-based templating connects Knockout to third-party template engine, such as jQuery Templates, MustacheJS, or underscore.
In this post, you will learn the basics of using templates in your HTML application using JavaScript.
Named Template Example
Templates can be defined as script elements with a type of text/html so the markup is not executed as JavaScript. You can then reference the data using Knockout data-bind attributes as you have learned in the earlier parts of this series.
For example, you might have a table with rows. Each row might show product data. In the example, the script tag shows how you might have one row for each product.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script type="text/html" id="product-template"> | |
<tr> | |
<td data-bind="text: product"></td> | |
<td data-bind="text: type"></td> | |
</tr> | |
</script> |
NOTE: The script tag uses type="text/html"
.
We can bind the data in the cell to items in the array.
The container element can then specify the identifier of the template and use control property, such as foreach, to walk through the data.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<table data-bind="template: { name: 'product-template', foreach: productArray }"> | |
</table> |
Here’s the complete example:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<body> | |
<h2>Products</h2> | |
<table data-bind="template: { name: 'product-template', foreach: productArray }"> | |
</table> | |
<script type="text/html" id="product-template"> | |
<tr> | |
<td data-bind="text: product"></td> | |
<td data-bind="text: type"></td> | |
</tr> | |
</script> | |
<script src="Scripts/knockout-2.2.1.debug.js"></script> | |
<script type="text/javascript"> | |
function ViewModel() { | |
this.productArray = ko.observableArray([ | |
{ product: "Widget", type: "Tool" }, | |
{ product: "Bolt", type: "Fastener" }, | |
{ product: "Washer", type: "Fastener" }, | |
{ product: "Screwdriver", type: "Tool" } | |
]); | |
} | |
ko.applyBindings(new ViewModel()); | |
</script> | |
</body> |
Which takes the template and creates a row for each item of data in the array:
Knockout Template Parameters
Before we dive into code, here’s a quick summary of the parameters you can pass to use Knockout templates.
If you just supply a string value, Knockout will render the template identifier and will use the current model object for the template.
For more control, pass a JavaScript object with some combination of the following properties:
name
— the ID of an element that contains the template you wish to render.data
— an object to supply as the data for the template to render. If you omit this parameter, KO will look for aforeach
parameter, or will fall back on using your current model object.if
— if this parameter is provided, the template will only be rendered if the specified expression evaluates totrue
(or atrue
-ish value). This can be useful for preventing a null observable from being bound against a template before it is populated.foreach
— instructs KO to render the template in “foreach” mode.as
— when used in conjunction withforeach
afterRender
,afterAdd
, orbeforeRemove
— callback functions to be invoked against the rendered DOM elements.
Details are provided in the Knockout page on template binding.
Nesting Templates
When nesting foreach
templates, you can refer to items at higher levels in the hierarchy.
In the following example, we show how you can use the product-template and then a parts-template using nested foreach control flows.
Note that the highlighted section shows how to reference the product name from within the parts template.
Here’s the body portion of the example.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<body> | |
<h2>Products</h2> | |
<table data-bind="template: { name: 'product-template', | |
foreach: productArray, as: 'productA' }"> | |
</table> | |
<script type="text/html" id="product-template"> | |
<tr> | |
<td data-bind="text: product"></td> | |
<td data-bind="text: type"></td> | |
<td> | |
<ul data-bind="template: { name: 'parts-template', foreach: parts, as: 'part' }"> | |
</ul> | |
</td> | |
</tr> | |
</script> | |
<script type="text/html" id="parts-template"> | |
<li> | |
<span data-bind="text: part"></span> | |
in | |
<span data-bind="text: productA.product"></span> | |
</li> | |
</script> | |
<script src="Scripts/knockout-2.2.1.debug.js"></script> | |
<script type="text/javascript"> | |
function ViewModel() { | |
this.productArray = ko.observableArray([ | |
{ product: "Widget", type: "Tool", | |
parts: ['Foo', 'Whatchmacallit' ] }, | |
{ product: "Bolt", type: "Fastener", | |
parts: ['Bolt', 'Washer', 'Wingnut' ] }, | |
{ product: "Washer", type: "Fastener", parts: ['Washer'] }, | |
{ product: "Screwdriver", type: "Tool", parts: [] } | |
]); | |
} | |
ko.applyBindings(new ViewModel()); | |
</script> | |
</body> |
The result is:
Using Third Party Templating
Since KO is open source you can probably find support for your favorite templating engine already available. You can choose among underscore.js or
Mustache is a “logic-less” template syntax. “Logic-less” means that it doesn’t rely on procedural statements (if, else, for, etc.): Mustache templates are entirely defined with tags. Mustache is implemented in different languages: Ruby, JavaScript, Python, PHP, Perl, Objective-C, Java, .NET, Android, C++, Go, Lua, Scala, etc. Mustache.js is the JavaScript implementation.
You can get Mustache for your Visual Studio project through NuGet.
The ko.mustache extension by Marcin Wtorkowski adds support for mustache templating engine.
ko.mustache.js is a template engine for knockoutjs. It enables you to use mustache.js template library in place of jQuery.tmpl.
Here’s an example using Mustache and ko.mustache.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<title>ko.mustache.js example</title> | |
</head> | |
<body> | |
<!– place for rendered template –> | |
<div data-bind='template: "productTemplate"'></div> | |
<!– mustache template –> | |
<script id='productTemplate' type='text/html'> | |
{{ product }} has {{ quantity }} | |
<button data-bind='click: sellItem'>Sell Item</button> | |
</script> | |
<script type="text/javascript" src="Scripts/mustache.js"></script> | |
<script type="text/javascript" src="Scripts/knockout-2.2.1.js"></script> | |
<script type="text/javascript" src="Scripts/ko.mustache.js"></script> | |
<script> | |
ko.setTemplateEngine(new ko.mustacheTemplateEngine()); | |
</script> | |
<!– knockout model and bindings –> | |
<script type='text/javascript'> | |
var viewModel = { | |
product: 'Widet', | |
quantity: ko.observable(4), | |
sellItem: function () { | |
if(this.quantity() > 0) { | |
this.quantity(this.quantity() –1); | |
} | |
} | |
}; | |
ko.applyBindings(viewModel); | |
</script> | |
</body> | |
</html> |
With this result:
When you click on the Sell Item button, it will decrement the counter using knockout as you would expect.
Summary
You can use template feature in Knockoutjs to render your data. Templates are a straight forward way to build complex UI structure, often with repeating or nested blocks. You can use templates to show repeating data, such as data in tables or portfolios.
You can use name-based templating or string-based templating.