JavaScript Templating (blink sauce enabled)

By Jordan Boesch

Autobiography

  • I'm a front-end developer for VendAsta
  • I write a bunch of little jQuery plugins to give back to the community
    www.boedesign.com
  • When I eat toast in the morning, my spread of choice is JavaScript
  • Some of my own side projects are:

    7shifts.com

    online employee scheduling

    taxime.ca

    taxi fare estimation

What is JavaScript templating?

The ability to render HTML and replace content with data created by JavaScript.

Why?

Because doing this gets hairy...

// Make an ajax post to add a user
$.post('json/add_person.json', { person: 'bob', age: 55 }, function(data){
    // Make an HTML template on the fly and add user data to it
    var person_html = '<div id="person-' + data.user.id + '" class="person">';
    person_html += '<h3>Example</h3><strong>' + data.user.name + '</strong>';
    // If we find that this user has some children, we need to add them to the HTML output
    if(data.user.children && data.user.children.length){
        $.each(data.user.children, function(i, o){
            person_html += '<div class="child">' + o.child_name + '</div>';
        })
    }
    person_html += ' <span>' + data.user.age + '</span></div>';
    // With the HTML template we just created, append it to the people list
    $('#people').append(person_html);
}, 'json');
            

No worries!

There are solutions out there to make your JavaScript code less hairy.

"Oh plz dont take away my hair!" -Harry J. Script

Some popular libraries

jQuery tmpl

The most common function

$.tmpl(template, data);

template: The HTML markup or text to use as a template.
data: The data to render. This can be any JavaScript type, including Array or Object.

jQuery tmpl example

Let's dive head-first into the code

Simple example

// First include the jQuery tmpl plugin
// OMG Microsoft is doing something open source?!
<script src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js"></script>

<script type="text/javascript">     
    var html_template = "<li>${name}</li>";
    var new_tmpl = $.tmpl(html_template, { name: 'jimbo' });
    alert(new_tmpl); // outputs <li>jimbo</li>
</script>

...Cool, but what if I don't want to store my HTML template in JavaScript?

How 'bout these apples?

Storing the template in HTML

// The browser has no idea how to render this script type.. perfect for sneaking templates in :D
<script id="person-tmpl" type="text/x-jquery-tmpl">
       <div id="person-${user.id}" class="person">
           <h3>Example</h3>
           <strong>${user.name}</strong>
           {{each(i, c) user.children}}
               <div class="child">${c.child_name}</div>
           {{/each}}
           <span>${user.age}</span>
       </div>
 </script>
 
<script type="text/javascript">
       // Shortcut for $(document).ready
       $(function(){ 
           $.post('json/add_person.json', { person: 'bob', age: 55 }, function(data){
               $.tmpl($('#person-tmpl'), data).appendTo('#people');
           }, 'json'); 
       });
</script>

Conditional logic

<script id="person-tmpl" type="text/x-jquery-tmpl">
       <div id="person-${user.id}" class="person">
           <h3>Example</h3>
           {{if user.name}}
               <strong>${user.name}</strong>
           {{else}}
               <strong>No name found</strong>  
           {{/if}}
           {{each(i, c) user.children}}
               <div class="child">${c.child_name}</div>
           {{/each}}
           <span>${user.age}</span>
       </div>
 </script>
 

Caching

Re-querying the DOM each time isn't always necessary

$.template(name, template)

name: A string naming the compiled template.
template: The HTML markup and/or text to be used as template. Can be a string, or an HTML element (or jQuery object wrapping an element) whose content is to be used as template.

Caching


<script id="person-tmpl" type="text/x-jquery-tmpl">
       <div id="person-${user.id}" class="person">
           <h3>Example</h3>
           <strong>${user.name}</strong>
           {{each(i, c) user.children}}
               <div class="child">${c.child_name}</div>
           {{/each}}
           <span>${user.age}</span>
       </div>
</script>
 
<script type="text/javascript">
     
     // Shortcut for $(document).ready
     $(function(){ 
         // Store the template with a keyname and use it later
         $.template('person-template', $('#person-tmpl'));
         
         $.post('json/add_person.json', { person: 'bob', age: 55 }, function(data){
             $.tmpl('person-template', data).appendTo('#people');
         }, 'json'); 
     });
</script>

Caching

So how much quicker is it?

<script type="text/javascript">  
          
$.template('person-template', $('#person-tmpl'));

// Run this 1000 times (288ms)
$.tmpl('person-template', data);

// Run this 1000 times (676ms)
$.tmpl($('#person-tmpl'), data);

</script>

A known issue with jQuery tmpl

Use django? The jQuery tmpl {{ }} braces conflict with django template tags!
Issue logged here: http://github.com/nje/jquery-tmpl/issues#issue/17

This breaks...

<script type="text/x-jquery-tmpl">
    {{each(i, c) user.children}}
        <div class="child">${c.child_name}</div>
    {{/each}}
</script> 

This is "hacky" but it won't break...

<script type="text/x-jquery-tmpl">
    [[each(i, c) user.children]]
        <div class="child">${c.child_name}</div>
    [[/each]]
</script>

<script type="text/javascript">
    $(function(){
        // Go find any script template blocks
        // and replace [[ with {{ and ]] with }}
        $("script").each(function(){
            var new_replaced_txt = $(this).text().replace(/\[\[/g, "{{").replace(/\]\]/g, "}}");
            $(this).text(new_replaced_txt);
        });
        // Ok we've dodged django, now we're ready to call $.tmpl on our code.
    });
</script>

Support for browsers with JavaScript disabled?

HELL NO! SCREW 'EM!... but not really.

If you're wanting to support that 2% of people that have JavaScript disabled, Mustache JS might be a better alternative - sorry for wasting your time ;)

http://mustache.github.com/
Available in Ruby, JavaScript, Python, Erlang, PHP, Perl, Go, Lua, ooc, C++, ActionScript, Java, ColdFusion, Scala, and for node.js.

Benchmark of a tonne of JS Templating plugins

Thanks for letting me steal your stat 'n shit. K THX BI.
http://www.viget.com/extend/benchmarking-javascript-templating-libraries/

FIN

Please place your 3D glasses in the box beside the door on your way out.

http://www.twitter.com/jboesch
http://www.boedesign.com
http://www.github.com/jboesch