Getting Started on Line-of-Business HTML5 App - Part 12 Show Data in Templates Using JsRender
Wouldn’t it be great to have the power of those data controls in your HTML5 application? I’d like to be able to build out a table or have my user input data into a form.
In this post, I’ll explore how to do client side data binding using JsRender.
Microsoft donated jQuery Templates to be Open Source code and adopted by jQuery. The next-generation of jQuery Templates is becoming JSRender and JsViews. The work is still early on the new version and changes are no doubt coming. (JsViews are interactive data-driven views, built on top of JsRender templates.)
JsRender works in the same way as jQuery Templates. But the advance for JsRender is that it uses pure string-based rendering without any DOM (or even jQuery) dependency. No dependency on jQuery.
And you can run it on Node.js on the server.
Why Use Templates?
In the previous post, Part 11 Serving up JSON Using ASP.NET Web API, I used jQuery AJAX to retrieve my data from a Web service. And I ended up using code like this to insert the incoming data into my Web page.
function (data) {
// On success, 'data' contains a list of events.
$.each(data, function (key, val) {
// Format the text to display.
var str = val.Title + ': ' + val.Location;
// Add a list item for the product.
$('<li/>', { html: str }).appendTo($('#events'));
});
});
The code manipulates the HTML DOM by adding list items into a <ul> tag whose ID is events. But you can not see that in the code.
But how about if that same code looked like this:
<ul id="events">
<script id="eventListTemplate" type="text/x-jsrender">
<li>
{{:title}}: {{:location}}
</li>
</script>
</ul>
Would that be easier to read and maintain? And what if I could do more complex rendering? Maybe I wanted to walk through a heirarchical tree of data. What if there was something flexible enough to render my data the way I think of data?
Enter JsRender.
So What are The Parts for JsRender?
Let’s start with a simple example. We’ll need are three parts to JsRender to work.
- The template.
- A container.
- Your data.
- Some code to render your data, insert it into the container, based on what you have defined in your template.
Before you get started, you will want to get the the latest stable version of JsRender from Github.
And add it to your header.
<script src="Source/jsrender.js" type="text/javascript"></script>
The Template
Let’s first describe the template. The template is a specially formatted script that JsRender understands and executes. You can use HTML (or any text string) and combine it with your data.
<script id="contactTemplate" type="text/x-jsrender">
<div>
{{:#index+1}}: <b>{{:name}}</b> ({{:birthYear}})
</div>
</script>
When the template executes, JsRender take each item identified by the colon character and replaces it with the data. Note the {{: ...}} and {{> ...}} tags. The rendering engine looking for {{:some.data.path}} , and supports converter functions, and almost any JavaScript expression, as in {{myConverter:someExpression}} . It is not HTML-encoded by default, so you can use more complex expressions.
There is now a zero-based index, identical to the index on view objects when using JsViews. This change is thanks to expression support which has made getting a 1-based index very easy, as in: {{:#index + 1}} .
Next the place where the text will be inserted. Place this is the body.
<div id="contactList"></div>
We’ll write a jQuery statement to change this HTML so it displays the data from the template.
Our Data
Let’s start by populating a JavaScript object called contacts.
<script type="text/javascript">
var contacts = [
{ name: "Fred", birthYear: "1998" },
{ name: "Sam", birthYear: "1999" },
{ name: "Kim", birthYear: "1976" }
];
Then we can render the data in Javascript. This part does require jQuery because we are using it to modify the HTML DOM.
// Render the template with the contact data and insert
// the rendered HTML under the "contactList" element
$("#contactList").html(
$("#contactTemplate").render(contacts)
);
</script>
More Complex Templates
JavaScript Expressions
JsRender template tags now supports almost any JavaScript expression (and also allow parens, to any depth).
For example, you can write: {{if price > 3 && price < (maxPrice - 10)}}Special deal{{/if}}.
Nested, Heirarchical Data
Templates can be used to render a series of items, which can often contain nested and hierarchical data (object graphs). Applications often retrieve object graphs where objects have properties whose values are arrays of objects that may also contain other arrays of objects. These scenarios can quickly become difficult to manage when nesting multiple {{for}} statements. Consider a customer object may have orders, which have order items, which have a product, which has warehouses. This hierarchical data could be rendered by using multiple {{for}} tags.
Traverse Data
And you can traverse your data. For example, you go back up the object hierarchy using #parent or identify an array element using square brackets, such as
<img src="{{:#parent.parent.data[2].eventpic.smallUrl}}"/>
Conditional Rendering
You can also add conditional information using {{if element}} {{/if}} . The formatting can then be conditional based on the existence of a value in your data.
For our example with signing up at the event.
<!-- event template builds the rows of the table -->
<script id="eventTemplate" type="text/x-jsrender">
<tr>
<td>{{:#index+1}}</td>
<td>{{:eventName}}</td>
<td>{{:location}}</td>
<td>{{:eventDate}}</td>
<td>
{{if full }}
<a href="{{:registrationID}}">wait list</a>
{{else}}
<a href="{{:registrationID}}">register</a>
{{/if}}
</td>
</tr>
</script>
<!-- Table for the data -->
<table><tbody class="header">
<tr><th></th><th>Event</th><th>Location</th><th>Date</th><th>Register</th>
</tr></tbody>
<tbody id="eventList"></tbody>
</table>
<!-- Event data, and inserting the table into the tbody -->
<script type="text/javascript">
var events = [
{ eventName: "HTML5 Days", location: "Denver, CO", eventDate: "8/12/2012", registrationID: "2345" },
{ eventName: "Windows 8 Days", location: "Chicago, IL", eventDate: "6/1/2012", registrationID: "2346" },
{ eventName: "Startup Days", location: "Silicon Valley, CA", eventDate: "6/12/2012", full: "yes", registrationID: "2347" },
{ eventName: "Startup Days", location: "New York, NY", eventDate: "7/12/2012", registrationID: "2348" }
];
// Render the template with the event data and insert
// the rendered HTML under the "eventList" element
$("#eventList").html(
$("#eventTemplate").render(events)
);
</script>
I also format some of the HTML conditionally. If the event is full, I ask the user to join a waiting list.
How to Get JSRender
Site includes demos. To view demo pages, see https://borismoore.github.com/jsrender/demos/index.html.
Learn more about JsRender at Boris Moore’s blog.
For More Information
An excellent article by John Papa, Using JsRender with JavaScript and HTML, in MSDN Magazine.
My colleague Dan Wahlin provides a tutorial on using JsRender. See Reducing JavaScript Code Using jsRender Templates in HTML5 Applications.
Also see Tim Kulp’s post on Plugin to Data Binding with jQuery for other ways to bind data.
Next Up
DataTables
Bruce D. KyleISV Developer Evangelist | Microsoft Corporation