Single Page App – HTML Templates With Logic Using Underscore, LoDash

Underscore.jsUnderscore complement to JavaScript’s standard library. And it also gives you simple templating.

The Underscore template function compiles JavaScript templates into functions that can be evaluated for rendering. Template functions can both interpolate variables or execute arbitrary JavaScript code. That allows you to put more logic than you can with Mustache.

Comparison to Mustache, Handlebars

Mustache and Handlebars are what are known as “logic-less template engines.” With those libraries you cannot include any overly complex logic in the template. You get the most basic control structures needed to output data, keeping the HTML (or other content) clean.

Underscore is different. It’s a JavaScript library in itself, like Prototype or jQuery, and comes with it’s own templating engine. The templates have access to any method or helpers within the library, meaning the templates are strictly tied to JavaScript and house a lot more of the logic.

Template Function

You can get Underscore from GitHub or Underscore on NuGet.

The template function has the following signature:

_.template(templateString, [optional] data, [optional] settings) 

templateString holds the template. settings allow you to override the global settings. If you omit data, you compile a template that has to be applied to data as a function.

For example, the following template says “Hello” followed by the a variable named user.

var t1 = _.template("Hello <%=user%>!"); 

You can then apply data.

 t1({ user: "<Jane>" })

And the result is

'Hello <Jane>!'

Interpolate, Evaluate, Escape

You can insert data and code dynamically in three ways. Template functions can:

  • Interpolate variables, using <%=interpolate%>
  • Execute arbitrary JavaScript code, with <%evaluate%>.
  • Insert the result of an expression, but escape & < > ” ‘ / by using <%-escape%>

Loops and Logic

The escape directive lets you insert arbitrary code. So you can use _.forEach to iterate through an array and provide logic for you to omit the trailing comma in this user list:


var t2 = _.template(
"Users: <%_.forEach(users, function (u,i) {%>"
+ "<%if (i>0) {%>, <%}%>"
+ "<%=u%>"
+ "<%})%>"
);

Sample

Using the following data:


{
"products": [
{
"id": 1,
"name": "Squirt gun",
"category": "Toy",
"price": 45.05,
"description":
"<p>This is a <strong>squirt</strong> gun. Shoots water.</p>"
},
{
"id": 2,
"name": "Action figure",
"category": "Toy",
"price": 65.96,
"description": "<p>This is an extraordinary action figure.</p>"
},
{
"id": 3,
"name": "Doll",
"category": "Toy",
"price": 35.68,
"description":
"<p>This is a <emphasis>doll</emphasis> for your doll house.</p>"
},
{
"id": 4,
"name": "Lettuce",
"category": "Grocery",
"price": 3.49,
"description": "<p>This is a vegetable.</p>"
}
]
}

view raw

ojs-data.json

hosted with ❤ by GitHub

You can combine the template functions to create a standard template.


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Standard Template</title>
</head>
<body>
<h3>Products</h3>
<div id="productDiv"></div>
<script src="Scripts/underscore.js"></script>
<script src="Scripts/jquery-2.0.3.js"></script>
<script>
var template = "<ul>" +
"<% for (var index = 0; index < productsList.length; index++){ %>" +
"<% var product = productsList[index]; %>" +
"<% var tenPercentDiscount = product.price * .9; %>" +
"<li><span class='id'><%= product.id %></span> " +
"<span><strong><%= product.name %></strong></span><br/>" +
"<span>Product price = <%=product.price%>; " +
"Discount price = <%= tenPercentDiscount %></span><br/>" +
"<%=product.description%>" +
"<% } %>" +
"</ul>";
$.getJSON('Data/products.txt', function (data) {
var products = data.products;
var output = _.template(template, { productsList: products });
$("#productDiv").html(output);
});
</script>
</body>
</html>

The result is:

image

 

If you want to use straight JavaScript and don’t want the output on the line we need to use <%. Also, if you use <% you MUST add a semi-colon ; at the end of the JavaScript line and then follow it with the %> to enclose the line of JS.

<%= is the way we actually print out the variables to the template. With this tag, DO NOT put a semi-colon ; at the end of the line or the template will break.

Changing the Syntax

You can change the syntax used by Underscore. So want to use Mustache-style curly braces instead of angle brackets?

Here’s how:


_.templateSettings = {
interpolate : /\{\{(.+?)\}\}/g
};

Interaction:

    >  _.template("Hello {{user}}!", { user: "<Jane>" })
    'Hello <Jane>!'

You can change the syntax of each kind of insertion. The syntax will be handled in the order of

  1. escape
  2. interpolate
  3. evaluate.

Pre-compilation

You have the option to compile a template once, in advance, instead of doing so many times in the clients. Each compiled template function has the property source which holds the source of that function. The following is a fragment of server-side template that is used to produce a web page. The result could be stored or cached somewhere.

<script>
    var clientTmpl = <%= _.template(clientTmplDef).source %>;
</script>

In the example, clientTmplDef holds the definition of a client-side template.

Sample Code

You can find sample code for this post on DevDays GitHub: https://github.com/devdays/object-javascript/tree/master/Underscore

References