Meet JsRender -- the Next Version of jQuery Templates
Explore JsRender, which can help you minimize JavaScript coding in HTML5 web apps
February 20, 2012
RELATED: "4 More Web Development Tips to Improve Your jQuery Coding" and "Better Mobile Website Development Using the jQuery Mobile Library."
Back in 2011 I wrote an article for Dev Pro 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.
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 block in the page with a type of text/x-jquery-tmpl, as shown next:</p><pre class="brush: text"><script id="OrderSummaryTemplate" type="text/x-jquery-tmpl"> <!-- Template goes here -->
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
element using the JsRender binding syntax:
<div>{{=FirstName}}</div>
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.
{{else}} {{/if}}{{/each}}
Template Tag |
---|
Figure 2: Template tags available in JsRender |
{{=fieldNameOrExpression}} |
{{=fieldNameOrExpression!}} |
{{#if condition}} |
{{else}} |
No items selected |
Ordered items! |
Used to add additional conditional logic into JsRender templates. |
{{#each}} |
{{=mi.NumberOrdered}} at ${{=mi.Price}} |
Used to iterate over a data array and render the content for each data item. |
{{#each tmpl="#NestedTemplateID"}} |
Rendering a JsRender Template
Once a template is defined using a 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.</p><p>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.</p><pre class="brush: text">$("#OrderSummaryOutput").html($("#OrderSummaryTemplate").render(json)); </pre><p>The JSON data can be created locally or retrieved from a remote service call, as shown in Figure 3.</p><pre class="brush: text" language="text" linenumbers="none" title="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));}</pre><h3>JsRender in Action</h3><p>You can <a href="https://tinyurl.com/7x9mkaw" target="_blank">download a sample application</a> that I created to demonstrate JsRender in action or download it via the Download button at the top of this article. (This application is part of the sample code available with my company's jQuery Web Programming training course.) The sample app is an ASP.NET MVC 3 project named OrderUp that leverages jQuery heavily and uses JsRender to display order details. In Figure 4, you can see an example of the output that's rendered. Figure 5 shows the JsRender template used to generate the Totals and Delivery Information sections shown in Figure 4.</p><figure class="captioned-image caption-none"><img alt="Figure 4: An example of JsRender in action" src="https://cet.informabi.com/sites/devproconnections.com/files/uploads/2013/11/figure4.jpg" style="width: 548px; height: 541px;" title="Figure 4: An example of JsRender in action"><figcaption class="image-description">Figure 4: An example of JsRender in action</figcaption></figure><p>The template code that handles iterating through purchased products and accessories is shown in Figure 6.</p><pre language="text" linenumbers="none" title="Figure 6: Using the if and each JsRender template tags to perform conditional logic and iterate through collections"><script id="OrderSummaryTemplate" type="text/x-jquery-tmpl"> <!-- Code from Listing 5 --><tr> <td class="OrderHeader">Items Ordered</td></tr>{{#if MainItems.length === 0}} <tr> <td>No items selected</td> </tr>{{else}} {{#each MainItems tmpl="#ItemsTemplate"}}{{/if}}<tr> <td> </td></tr> <tr> <td class="OrderHeader">Accessories Ordered</td></tr>{{#if AccessoryItems.length === 0}} <tr> <td>No accessories selected</td> </tr>{{else}} {{#each AccessoryItems tmpl="#ItemsTemplate"}}{{/if}} <tr> <td> {{=Name}} - {{=NumberOrdered}} ordered at $ {{=Price}} per item </td> </tr>
This code uses the if and each tags. Looking through the code, you'll see that the each tag references another template named ItemsTemplate using the each tag's tmpl property. Here's an example of using tmpl:
{{#each MainItems tmpl="#ItemsTemplate"}}
The ItemTemplate child template is reusable and handles writing out the products and accessories that were purchased. As the each tag iterates through the different items, it passes each item to the child template for rendering.
The template is rendered to a div with an ID of OrderSummaryOutput using the code shown in Figure 7. The code first creates a JSON object by retrieving data from controls in a checkout wizard, then calls the render() function provided by JsRender.
function LoadApprovalDiv() { var subTotal = parseFloat($('#SubTotal').text()); $('#ClientSubTotal').val(subTotal.toFixed(2)); var salesTaxRate = parseFloat($('#SalesTaxRate').val()) / 100; var salesTaxAmount = (subTotal * salesTaxRate) * .9; var deliveryFee = parseFloat($('#DeliveryFee').val()); var adminFee = ((subTotal + salesTaxAmount + deliveryFee) * .05); var total = (Round(subTotal) + Round(salesTaxAmount) + Round(deliveryFee) + Round(adminFee)); $('#ClientTotal').val(total); var deliveryAddress = $('#Delivery_Street').val(); //See if they entered a suite if ($('#Delivery_Suite').val() != '') deliveryAddress += ', Suite ' + $('#Delivery_Suite').val(); deliveryAddress += ' ' + $('#Delivery_City').val() + ' ' + $('#Delivery_StateID option:selected').text() + ' ' + $('#Delivery_Zip').val(); var creditCard = $('#Payment_CreditCardNumber').val(); var abbrCreditCard = '*' + creditCard.substring(creditCard.length - 5);var json = { 'FinalSubTotal' : subTotal.toFixed(2), 'FinalSalesTax' : salesTaxAmount.toFixed(2), 'FinalTotal' : total.toFixed(2), 'DeliveryFee' : deliveryFee.toFixed(2), 'AdminFee' : adminFee.toFixed(2), 'DeliveryName' : $('#Delivery_Name').val(), 'DeliveryAddress': deliveryAddress, 'CreditCard' : abbrCreditCard, 'DeliveryDate' : $('#Delivery_DeliveryDate').val(), 'DeliveryTime' : $('#Delivery_DeliveryTime option:selected').text(), 'MainItems' : GenerateJson('Main'), 'AccessoryItems' : GenerateJson('Accessory') };//jQuery template example $("#OrderSummaryOutput").html($("#OrderSummaryTemplate").render(json));}
In addition to the JsRender features I've shown here, several others are available, including the ability to define custom tags, helper tags, and functions. Additional details about these features are outside the scope of this article, but you can read more about them at the JsRender site on GitHub. The site even includes examples of using JsRender without jQuery (although I'm a huge fan of jQuery and highly recommend it!).
Improve Productivity, Reduce Coding
If you're working with dynamic web applications that leverage a lot of client-side functionality and Ajax, you'll find that JsRender can significantly increase your productivity and eliminate a lot of code that you'd otherwise have to write. Although JsRender is still new (at the time this article was written, anyway), it's definitely worth looking into. Next, we'll switch topics and focus on HTML5's canvas element, which expands your options for rendering text, images, shapes, and more.
About the Author
You May Also Like