2. Why use a template?
• Render data as markup
• Separation of display logic from
business logic
• Reusable markup (in theory)
• Maybe it’s cleaner?
• It’s definitely faster than...
3. The Other Options
• String Concatenation
• Array.join
• DOM Manipulation
• jQuery.append
6. DOM Manipulation
var p = document.createElement('P');
var hello = document.createTextNode('Hello, ');
var em = document.createElement('EM');
var world = document.createTextNode(this.name + '!');
em.appendChild(world);
p.appendChild(hello);
p.appendChild(world);
body.appendChild(p);
12. Scope (this)
• Rendered template function is executed in the scope of
the data object
• Dropped with for performance, replaced with this
var str = '<p>Hello, <em>{%= this.name %}!</em></p>';
13. Two Types of Tags
• Output tags pass their values to
the returned output
• Functional tags execute
arbitrary JavaScript, but do not
output any value
14. Output Tags {%= ... %}
// Output is added to the output
{%= this.property %}
// Ternaries can be used for quick conditionals
{%= this.property ? this.property : "N/A" %}
// JavaScript is executed and added to output
{%= (new Date()).getTime() - (this.birthdate).getTime() %}
15. Functional Tags {% ... %}
// Value is not added to output
{% var pie = 22/7; }
// Semi-colons not required, but encouraged for best practice
{% var greeting = "Hello, " + this.name }
// WIN
// Double-quotes are STRICTLY REQUIRED
{% var greeting = 'Hello, ' + this.name }
// FAIL
// Single-quotes allowed in strings
{% var greeting = "I'm with " + this.name }
// WIN
16. Looping an Array
{% for (var i = 0, n = this.images.length; i < n; ++i) { %}
{% var img = this.images[i]; }
<img src="{%= img.src %}" alt="{%= img.description %}">
{% } %}
26. Data Input (Object)
var str = '<p>Hello, <em>{%= this.name %}!</em></p>';
var data = { name: 'world' };
var html = $.template(str, data, true);
// <p>Hello, <em>world!</em></p>
27. Data Input (Array of objects)
var str = '<p>Hello, <em>{%= this.name %}!</em></p>';
var data = [
{ name: 'world' },
{ name: 'Dolly' },
{ name: 'mom' }
];
var html = $.template(str, data, true);
// <p>Hello, <em>world!</em></p>
// <p>Hello, <em>Dolly!</em></p>
// <p>Hello, <em>mom!</em></p>
29. Output (function)
// This template...
var str = '<p>Hello, <em>{%= this.name %}</em>!</p>';
var func = $.template(str);
// becomes...
function anonymous() {
var __ = [];
__.push("<p>Hello, <em>", this.name, "!</em></p>");
return __.join("");
}
// which can be used as...
var elem = func(data);
// or...
var html = func(data, true);
31. Output (DOM)
DOM output is wrapped in <jquery:template/> to allow
jQuery manipulation and to protect leading and trailing
fragments and elements
<jquery:template>
<p>Hello, <em>world!</em></p>
<p>Hello, <em>Dolly!</em></p>
<p>Hello, <em>mom!</em></p>
</jquery:template>
Hello, <em>world!</em>
// FAIL <em>world!</em>
<em>Goodbye</em>, cruel world!
// FAIL <em>Goodbye</em>
32. Output (DOM)
Attempted a patch to jQuery to wrap leading and trailing
fragments as text nodes, but then
var elem = $(tpl, obj).appendTo('body').hide();
// FAIL
would require rewrite of all of jQuery's DOM functions :(
33. Output (DOM)
Still breaks in some instances where markup is too invalid
$.template('<tr><td>{%= this.name %}</td></tr>', data)
.appendTo('<table/>');
<jquery:template>
<tr>
<td>Hello, world!</td>
<td>Hello, Dolly!</td>
<td>Hello, mom!</td>
</tr>
</jquery:template>
<table/>
// FAIL
// Invalid markup squirts out of the target element
34. Output (HTML)
Fix: use true to render as HTML
var html = $.template('<tr><td>{%= this.name %}</td></tr>',
data, true);
// <tr>
// <td>Hello, world!</td>
// <td>Hello, Dolly!</td>
// <td>Hello, mom!</td>
// </tr>
$('<table/>').append(html);
35. Known Issues
• Does not properly extract DOM
text in IE (fix on the way)
• Breaks in some cases where
markup is invalid