[javascript] How to use underscore.js as a template engine?

I'm trying to learn about new usages of javascript as a serverside language and as a functional language. Few days ago I heard about node.js and express framework. Then I saw about underscore.js as a set of utility functions. I saw this question on stackoverflow . It says we can use underscore.js as a template engine. anybody know good tutorials about how to use underscore.js for templating, especially for biginners who have less experience with advanced javascript. Thanks

The answer is


In it's simplest form you would use it like:

var html = _.template('<li><%= name %></li>', { name: 'John Smith' });
//html is now '<li>John Smith</li>'   

If you're going to be using a template a few times you'll want to compile it so it's faster:

var template = _.template('<li><%= name %></li>');

var html = [];
for (var key in names) {
    html += template({ name: names[i] });
}

console.log(html.join('')); //Outputs a string of <li> items

I personally prefer the Mustache style syntax. You can adjust the template token markers to use double curly braces:

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

var template = _.template('<li>{{ name }}</li>');

I am giving a very simple example

1)

var data = {site:"mysite",name:"john",age:25};
var template = "Welcome you are at <%=site %>.This has been created by <%=name %> whose age is <%=age%>";
var parsedTemplate = _.template(template,data);
console.log(parsedTemplate); 

The result would be

Welcome you are at mysite.This has been created by john whose age is 25.

2) This is a template

   <script type="text/template" id="template_1">
       <% _.each(items,function(item,key,arr) { %>
          <li>
             <span><%= key %></span>
             <span><%= item.name %></span>
             <span><%= item.type %></span>
           </li>
       <% }); %>
   </script>

This is html

<div>
  <ul id="list_2"></ul>
</div>

This is the javascript code which contains json object and putting template into html

   var items = [
       {
          name:"name1",
          type:"type1"
       },
       {
          name:"name1",
          type:"type1"
       },
       {
          name:"name1",
          type:"type1"
       },
       {
          name:"name1",
          type:"type1"
       },
       {
          name:"name1",
          type:"type1"
       } 
   ];
  $(document).ready(function(){
      var template = $("#template_1").html();
      $("#list_2").html(_.template(template,{items:items}));
  });


The documentation for templating is partial, I watched the source.

The _.template function has 3 arguments:

  1. String text : the template string
  2. Object data : the evaluation data
  3. Object settings : local settings, the _.templateSettings is the global settings object

If no data (or null) given, than a render function will be returned. It has 1 argument:

  1. Object data : same as the data above

There are 3 regex patterns and 1 static parameter in the settings:

  1. RegExp evaluate : "<%code%>" in template string
  2. RegExp interpolate : "<%=code%>" in template string
  3. RegExp escape : "<%-code%>"
  4. String variable : optional, the name of the data parameter in the template string

The code in an evaluate section will be simply evaluated. You can add string from this section with the __p+="mystring" command to the evaluated template, but this is not recommended (not part of the templating interface), use the interpolate section instead of that. This type of section is for adding blocks like if or for to the template.

The result of the code in the interpolate section will added to the evaluated template. If null given back, then empty string will added.

The escape section escapes html with _.escape on the return value of the given code. So its similar than an _.escape(code) in an interpolate section, but it escapes with \ the whitespace characters like \n before it passes the code to the _.escape. I don't know why is that important, it's in the code, but it works well with the interpolate and _.escape - which doesn't escape the white-space characters - too.

By default the data parameter is passed by a with(data){...} statement, but this kind of evaluating is much slower than the evaluating with named variable. So naming the data with the variable parameter is something good...

For example:

var html = _.template(
    "<pre>The \"<% __p+=_.escape(o.text) %>\" is the same<br />" +
        "as the  \"<%= _.escape(o.text) %>\" and the same<br />" +
        "as the \"<%- o.text %>\"</pre>",
    {
        text: "<b>some text</b> and \n it's a line break"
    },
    {
        variable: "o"
    }
);

$("body").html(html);

results

The "<b>some text</b> and 
 it's a line break" is the same
as the "<b>some text</b> and 
 it's a line break" and the same
as the "<b>some text</b> and 
 it's a line break"

You can find here more examples how to use the template and override the default settings: http://underscorejs.org/#template

By template loading you have many options, but at the end you always have to convert the template into string. You can give it as normal string like the example above, or you can load it from a script tag, and use the .html() function of jquery, or you can load it from a separate file with the tpl plugin of require.js.

Another option to build the dom tree with laconic instead of templating.


Lodash is also the same First write a script as follows:

<script type="text/template" id="genTable">
<table cellspacing='0' cellpadding='0' border='1'>
        <tr>
            <% for(var prop in users[0]){%>
            <th><%= prop %> </th>
            <% }%>
        </tr>
        <%_.forEach(users, function(user) { %>
            <tr>
                 <% for(var prop in user){%>
                    <td><%= user[prop] %> </td>
                <% }%>

            </tr>
        <%})%>
</table>

Now write some simple JS as follows:

var arrOfObjects = [];
for (var s = 0; s < 10; s++) {
    var simpleObject = {};
    simpleObject.Name = "Name_" + s;
    simpleObject.Address = "Address_" + s;
    arrOfObjects[s] = simpleObject;
}
var theObject = { 'users': arrOfObjects }
var compiled = _.template($("#genTable").text());
var sigma = compiled({ 'users': myArr });

$(sigma).appendTo("#popup");

Where popoup is a div where you want to generate the table


<!-- Install jQuery and underscore -->

<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="http://documentcloud.github.com/underscore/underscore-min.js"></script>

<!-- Create your template -->
<script type="foo/bar" id='usageList'>
<table cellspacing='0' cellpadding='0' border='1' >
    <thead>
      <tr>
        <th>Id</th>
        <th>Name</th>
      </tr>
    </thead>
    <tbody>
      <%
        // repeat items 
        _.each(items,function(item,key,list){
          // create variables
          var f = item.name.split("").shift().toLowerCase();
      %>
        <tr>
          <!-- use variables -->
          <td><%= key %></td>
          <td class="<%= f %>">
            <!-- use %- to inject un-sanitized user input (see 'Demo of XSS hack') -->
            <h3><%- item.name %></h3>
            <p><%- item.interests %></p>
          </td>
        </tr>
      <%
        });
      %>
    </tbody>
  </table>
</script>

<!-- Create your target -->

<div id="target"></div>

<!-- Write some code to fetch the data and apply template -->

<script type="text/javascript">
  var items = [
    {name:"Alexander", interests:"creating large empires"},
    {name:"Edward", interests:"ha.ckers.org <\nBGSOUND SRC=\"javascript:alert('XSS');\">"},
    {name:"..."},
    {name:"Yolando", interests:"working out"},
    {name:"Zachary", interests:"picking flowers for Angela"}
  ];
  var template = $("#usageList").html();
  $("#target").html(_.template(template,{items:items}));
</script>
  • JsFiddle Thanks @PHearst!
  • JsFiddle (latest)
  • JsFiddle List grouped by first letter (complex example w/ images, function calls, sub-templates) fork it! have a blast...
  • JsFiddle Demo of XSS hack noted by @tarun_telang below
  • JsFiddle One non-standard method to do sub-templates

with express it's so easy. all what you need is to use the consolidate module on node so you need to install it :

npm install consolidate --save

then you should change the default engine to html template by this:

app.set('view engine', 'html');

register the underscore template engine for the html extension:

app.engine('html', require('consolidate').underscore);

it's done !

Now for load for example an template called 'index.html':

res.render('index', { title : 'my first page'});

maybe you will need to install the underscore module.

npm install underscore --save

I hope this helped you!


I wanted to share one more important finding.

use of <%= variable => would result in cross-site scripting vulnerability. So its more safe to use <%- variable -> instead.

We had to replace <%= with <%- to prevent cross-site scripting attacks. Not sure, whether this will it have any impact on the performance


Everything you need to know about underscore template is here. Only 3 things to keep in mind:

  1. <% %> - to execute some code
  2. <%= %> - to print some value in template
  3. <%- %> - to print some values HTML escaped

That's all about it.

Simple example:

var tpl = _.template("<h1>Some text: <%= foo %></h1>");

then tpl({foo: "blahblah"}) would be rendered to the string <h1>Some text: blahblah</h1>


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to node.js

Hide Signs that Meteor.js was Used Querying date field in MongoDB with Mongoose SyntaxError: Cannot use import statement outside a module Server Discovery And Monitoring engine is deprecated How to fix ReferenceError: primordials is not defined in node UnhandledPromiseRejectionWarning: This error originated either by throwing inside of an async function without a catch block dyld: Library not loaded: /usr/local/opt/icu4c/lib/libicui18n.62.dylib error running php after installing node with brew on Mac internal/modules/cjs/loader.js:582 throw err DeprecationWarning: Buffer() is deprecated due to security and usability issues when I move my script to another server Please run `npm cache clean`

Examples related to functional-programming

Dart: mapping a list (list.map) Index inside map() function functional way to iterate over range (ES6/7) How can I count occurrences with groupBy? How do I use the includes method in lodash to check if an object is in the collection? Does Java SE 8 have Pairs or Tuples? Functional style of Java 8's Optional.ifPresent and if-not-Present? What is difference between functional and imperative programming languages? How does functools partial do what it does? map function for objects (instead of arrays)

Examples related to underscore.js

Add property to an array of objects Comparing two arrays of objects, and exclude the elements who match values into new array in JS using lodash .groupBy. how to add your own keys for grouped output? Remove Duplicate objects from JSON Array Lodash .clone and .cloneDeep behaviors find the array index of an object with a specific key value in underscore Bootstrap - Uncaught TypeError: Cannot read property 'fn' of undefined Map over object preserving keys Remove an item from array using UnderscoreJS Find by key deep in a nested array

Examples related to template-engine

React.js: Wrapping one component into another How to create global variables accessible in all views using Express / Node.JS? Truncate string in Laravel blade templates How to use underscore.js as a template engine? how to reference a YAML "setting" from elsewhere in the same YAML file? Is there a template engine for Node.js?