Back in 2011 I wrote an article for DevProConnections that demonstrated how you could use the jQuery Templates plug-in to reduce the amount of
JavaScript coding you need to do and simplify application maintenance in the process (see "Rendering Data on the Client with jQuery Templates"). Although the topics and code discussed in that article are still valid and relevant in today's client-centric applications, since that article was
written things have changed somewhat regarding the future of jQuery Templates. I've had several questions come up in jQuery classes that my firm
offers, at the DevConnections conference, and online about the future of jQuery Templates, so I thought I'd address the issue here and provide details
about the current roadmap for client-side templates.
You can get the full story in a blog post by Boris Moore,
the creator of jQuery Templates. In a nutshell, the jQuery UI team decided to go in a different direction with client-side templates and use an
alternative syntax to that provided by jQuery Templates. As a result, a new script has been released called JsRender that will ultimately replace
jQuery Templates (that's the current plan, anyway). I'll review a few things mentioned in my initial article for those who aren't familiar with
templates, then show examples of using the new JsRender functionality in an application. The good news is that if you're already using jQuery
Templates, a significant portion of your template code can easily be updated to use JsRender if you want to make the switch.
Why Use Client-Side Templates?
Nearly every language out there uses templates in some manner to minimize the amount of code that has to be written. By using templates, you can define
a template structure and use it to generate code, HTML, or other formats. If you've created ASP.NET applications, you're aware of how powerful and
productive templates are when it comes to generating HTML output. However, what if you want to use templates on the client side to generate HTML rather
than writing a lot of JavaScript to manipulate the Document Object Model (DOM)?
Since many HTML5 applications rely heavily on JavaScript to provide canvas, web storage, geolocation, and other features, minimizing the amount of code
in an application wherever possible can simplify maintenance down the road. For example, you may want to avoid having to write the code shown in Figure
1 to update a list of items dynamically in a page. This simple example could certainly grow bigger and bigger depending on the type of dynamic HTML
content being generated.
Figure 1: The standard way to update the DOM using JavaScript
var total;
$(order.Items).each(function()
{
var item = this;
$('#item' + item.ID)
.append('<div>' + item.Title +
'</div>');
total += item.Total;
});
$('#total').html(total);
Although templates have been available in jQuery for quite a while through various plug-ins, the JsRender template framework provides a new solution
that doesn't use Cascading Style Sheets (CSS) in strange ways or require a lot of knowledge about a template language. By using JsRender, you can
define HTML templates in web pages and use them to render HTML output dynamically at runtime.
You can download the JsRender script along with samples here.
Although I won't discuss it in this article, JsRender has a companion script called JsViews that can be used for data binding. You can read more about JsViews here.
Getting Started with JsRender
You can use client-side templates by referencing the JsRender script in your page and then defining a <script> block in the page with a type of
text/x-jquery-tmpl, as shown next:
<script id="OrderSummaryTemplate" type="text/x-jquery-tmpl">
<!-- Template goes here -->
</script>
Once the script tag is defined, you can place template code inside of it. Any HTML you add into the template is output automatically once the template
is rendered. Of course, adding static HTML doesn't accomplish much, so JsRender provides several tags that can be placed inside a template to define
data that should be output, perform conditional logic, iterate through items, render nested templates, and perform other actions.
Two general types of tag categories can be defined in templates: property binding tags and action tags. Property binding tags allow properties in a
JavaScript Object Notation (JSON) object to be bound into a template at runtime. They're similar to the <%# Eval("PropertyName") %> bindings that
you'll see in ASP.NET Web Forms pages. For example, the following template tag handles binding the FirstName property of a JSON object into a template:
{{=FirstName}}
Here is an example of a simple template that renders a FirstName property inside of a <div> element using the JsRender binding syntax:
<script id="OrderSummaryTemplate" type="text/x-jquery-tmpl">
<div>{{=FirstName}}</div>
</script>
Several different types of action tags are available as well, such as if and each. Both of these tags use a # character in the template tag:
{{#if}}
{{#each}}
Figure 2 lists the main template tags available with JsRender and examples of using them.
Rendering a JsRender Template
Once a template is defined using a <script> block, you can use JsRender's render() function to convert JSON data into HTML based on a template.
This is done by identifying the target element that will display the content that is generated, calling its html() function (when using jQuery), and
then passing the generated HTML by calling the render() function.
The render() function accepts the JSON data that the template will use to generate HTML content. The following code shows an example of putting all
this together. You'll see that an OrderSummaryOutput element is located by using a jQuery selector and that its html() function is passed the output
generated by a JsRender template named OrderSummaryTemplate.
$("#OrderSummaryOutput").html($("#OrderSummaryTemplate").render(json));
The JSON data can be created locally or retrieved from a remote service call, as shown in Figure 3.
Figure 3: Rendering a template using JsRender
$.ajax({
dataType: 'jsonp',
url: moviesServiceUrl,
jsonp: '$callback',
success: showMovies
});
// Within the callback, use .tmpl() to render the data.
function showMovies(data)
{
// Render the template with the "movies" data and insert
// the rendered HTML under the 'movieList' element
$("#movieList").html($("#moviesTemplate").render(data));
}