In this post, I give an overview over JavaScript HTML templating and list a few elegant solutions. I’ll also say which one I ended up choosing for a project of mine.
What is HTML templating?
The typical use case for templating in JavaScript is to display an array of objects on an HTML page. To get the look right, one usually prototypes in HTML what a displayed array element should look like and uses dummy data. Next, the HTML is turned into a
template by assigning names to places where the actual data should be put. For example:
<table>
<tr><td>First:</td><td>${first}</td></tr>
<tr><td>Last:</td><td>${last}</td></tr>
</table>
The templating engine has as input the template and an element from the data array and produces as output the “merged” HTML: The named places are replaced with data. One would expect the HTML to be produced by copying this prototype and filling in the data. But, surprisingly, with DOM implementations being complex and HTML parsing being efficient, the much faster solution is to produce HTML text and insert it into a document via
innerHTML. Accordingly, the template is also given as text to the engine. Because storing the template in JavaScript string literals is a bit clumsy, one often uses the following trick: If you store data inside a script tag, it will neither be displayed nor parsed (which might return in syntax errors), if you give it a MIME type that the browser does not recognize.
<script id="template" type="text/my-engine">
// The actual template: a mix of HTML and named places.
</script>
Some template engines directly take the id of such a script element as a parameter when translating data to an HTML string, others want the template as a text string, which can be produced as follows:
document.getElementById("template").innerHTML
Templating engines for JavaScript
Many templating engines have been developed for JavaScript. To evaluate them, a few requirements:
- Meta-elements such as ${first} should not use angle brackets, because this clashes with the surrounding HTML.
- As much logic as possible should be defined in JavaScript and not in the template. This is achieved by letting the template invoke externally defined JavaScript functions. If possible, these functions should also be kept separate from the data, because the data might come from an external source such as a web service.
Here are a few nice templating engines for JavaScript:
- John Resig’s Micro-Templating: has become a kind of a classic in the community and is notable for its briefness and simplicity. Disadvantages: Uses angle brackets, not very powerful, uses the with statement which is currently being phased out of JavaScript. I suspect that the script trick shown above originated in Micro-Templating.
- jQuote2: an improved version of Micro-Templating. Disadvantages: Angle brackets.
- Mustache: Is available for a variety of programming languages. Good syntax, but I don’t like having to mix data and functions. Furthermore, one can only invoke nullary functions in the template and not directly apply a function to a value.
- Normal Template: Looks nice, I like its syntax. I only decided against it because of jQuery Templates’ larger community (maybe not now, but definitely in the future).
- jQuery Templates: Due to the support of Microsoft, jQuery Templates has become an official jQuery plugin and thus the solution for templating in jQuery. Plus its syntax is nice and when it translates from data to HTML, one can hand in two objects: one with data and another one with helper functions. This keeps the logic away from the data.
- Google’s Closure Templates: You put template definition in separate files and Closure Templates compiles it to programming code. Positives: fast, language-neutral (works with Java and JavaScript). Negatives: compilation makes development slightly less convenient.
A tricky issue with many templating engines is how to display separators between elements of an array. In the follow-up post “
jQuery Templates: quick start and tips”, I present a solution that works for every engine (as long as it allows one to apply a function to an array), but is shown in the context of jQuery Templates.