Everyone loves client side templates. They are a great way to create html which is something JavaScript apps do all the time.

In February, a jQuery templating system was proposed and resulted in a tremendous amount of discussion, followed by an official templating engine for jQuery - jquery-tmpl.

Although jquery-tmpl is a solid templating engine, the discussion highlighted three extremely important facts about developers and client side templates:

Fact 1: Everyone has their favorite templating engine

There's a whole slew of templating languages people like:

Most of these template engines have distinct advantages and dissadvantages. It's impossible to expect a single template engine to meet everyone's needs.

Fact 2: Most templating engines provide the exact same features

I've yet to encounter a template that does't provide:

Fact 3: Very few people are familiar with the complexities of using templates

There's more than just syntax and magic tag preference that goes into a templating system. Consider:

jQuery.View

jQuery.View is a templating interface that takes care of the complexities of using templates, while being completely template agnostic.

This means that you can use any templating language in the exact same way and get all the additional features that jQuery.View provides.

Features

Downloads

Use

When using views, you're almost always wanting to insert the results of a rendered template into the page. jQuery.View overwrites the jQuery modifiers so using a view is as easy as:

$("#foo").html('mytemplate.ejs',{message: 'hello world'})

This code:

  1. Loads the template a 'mytemplate.ejs'. It might look like:

    <h2><%= message %></h2>
  2. Renders it with {message: 'hello world'}, resulting in:

    "<h2>hello world</h2>"
  3. Inserts the result into the foo element. Foo might look like:

    <div id='foo'><h2>hello world</h2></div>

jQuery Modifiers

You can use a template with the following jQuery modifier methods:

after $('#bar').after('temp.jaml',{});
append $('#bar').append('temp.jaml',{});
before $('#bar').before('temp.jaml',{});
html $('#bar').html('temp.jaml',{});
prepend $('#bar').prepend('temp.jaml',{});
replace $('#bar').replace('temp.jaml',{});
replaceWidth $('#bar').replaceWidth('temp.jaml',{});
text $('#bar').text('temp.jaml',{});

Template Locations

View can load from script tags or from files. To load from a script tag, create a script tag with your template and an id like:

<script type='text/ejs' id='recipes'>
<% for(var i=0; i < recipes.length; i++){ %>
  <li><%=recipes[i].name %></li>
<%} %>
</script>

Render with this template like:

$("#foo").html('recipes',recipeData)

Notice we passed the id of the element we want to render.

Packaging Templates

If you're making heavy use of templates, you want to organize them in files so they can be reused between pages and applications.

But, this organization would come at a high price if the browser has to retrieve each template individually. The additional HTTP requests would slow down your app.

Fortunately, StealJS can build templates into your production files. You just have to point to the view file like:

steal.views('path/to/the/view.ejs');

This will pre-process the view and insert it into a compressed single file with your other JS code.

Note: Steal 1.1 will even let you not load the view engine in production if all your templates are packaged.

Asynchronous

By default, retrieving requests is done synchronously. This is fine because StealJS packages view templates with your JS download.

However, some people might not be using StealJS or want to delay loading templates until necessary. If you have the need, you can provide a callback paramter like:

$("#foo").html('recipes',recipeData, function(result){
   this.fadeIn()
});

The callback function will be called with the result of the rendered template and 'this' will be set to the original jQuery object.

Just Render Templates

Sometimes, you just want to get the result of a rendered template without inserting it, you can do this with $.View:

var out = $.View('path/to/template.jaml',{});

Preloading Templates

You can preload templates asynchronously like:

$.View('path/to/template.jaml',{}, function(){});

When it comes time to use them in your app, they will be ready for the user.

Supported Templates

JavaScriptMVC comes with the following templates:

Mustache is supported in a 2nd party plugin.

Using Other Templates:

Integrating into $.View (and StealJS's build process) is easy, you just have to register your script like:

$.View.register({
	suffix : "tmpl",
	renderer: function( id, text ) {
		return function(data){
			return jQuery.render( text, data );
		}
	},
	script: function( id, text ) {
		var tmpl = $.tmpl(text).toString();
		return "function(data){return ("+
			tmpl+
			").call(jQuery, jQuery, data); }";
	}
})

Here's what each property does:

Conclusion

Templates are great, but there's a lot of extra work that goes into making a template engine useful. But, almost all of that extra work can be abstracted and reused.

This is exactly what jQuery.View is! It's a tool so future template engines don't have to worry about loading, caching, and bundling templates.

Even better, as it is a uniform template API, it enables plugin authors to write widgets that accept arbitrary template types.

I personally feel like this would be a good canidate for jQuery an official jQuery plugin of its own. Imagine customizing the layout of a widget by passing it a template:

$("#upcoming").srchr_search_result({
	modelType : Srchr.Models.Upcoming,
	resultView : "//srchr/views/upcoming.ejs"
});

P.S. This is actual code from our JavaScriptMVC version of Srchr. Read about it here. We customize search results panels with a Model used to retrieve searches and a view to output the results.