Skip to content

JavaScript Templates

TheCloudlessSky edited this page Mar 2, 2012 · 12 revisions

JavaScript Templates

If you're unfamiliar with JavaScript Templates (JST), I'd suggest you take a minute to familiarize yourself with the concept and the available libraries.

Adding Templates

Ignite collects all JSTs in a package and serves them as a single asset. Consider an Underscore.js Template located under views/templates/movies.jst:

<% _.each(obj, function (movie) { %>
<li><strong><%= movie.Name %></strong> (<%= movie.ReleaseYear %>)</li>
<% }); %>

And using the following Ignite configuration:

PackageContainer.Create()
    .JavaScript("core", new[] { "views/templates/movies.jst" })
    .Map(routes);

This produces the following HTML:

<script type="text/javascript" src="/assets/core.js?debug=templates/1f597908-19cb-4a65-930d-c417f223665f.js"></script>

Opening up this script shows the following:

(function(root) {
  var ns = root.JST || (root.JST = {});
  var lazyTemplate = function(tmpl) {
    var compiled = null;
    return function() {
      compiled || (compiled = _.template(tmpl));
      return compiled.apply(this, arguments);
    };
  };
  ns["views/templates/movies"] = lazyTemplate('<% _.each(obj, function (movie) { %>\n<li><strong><%= movie.Name %></strong> (<%= movie.ReleaseYear %>)</li>\n<% }); %>');
  // other templates here...
})(this);

Templates become compiled only after the first time they're used. Additionally, you can configure the package container to use a different extension other than jst:

PackageContainer.Create()
    .TemplateExtension("html.mustache")
    // etc...

Template Namespace

Templates are by default stored on the window.JST object. However, this namespace can be configured using the TemplateNamespace() method on the package container:

PackageContainer.Create()
    .TemplateNamespace("foo.bar")
    // etc...

This would change the generated template script:

var ns = root.foo.bar || (root.foo.bar = {});
// etc...

And now, all of the templates could be accessed via that namespace: foo.bar["views/templates/movies"].

Template Function

The default template function uses Underscore.js Templates: _.template. This function can be configured with the TemplateFunction() method on the package container:

PackageContainer.Create()
    .TemplateFunction("$.template")     // jQuery Templates (http://github.com/jquery/jquery-tmpl)
    .TemplateFunction("new Template")   // Prototype (http://www.prototypejs.org/)
    // etc...

This changes the generated template script:

compiled || (compiled = $.template(tmpl));

If you're using a template library that doesn't provide a direct method to compile templates, for example using Mustache.js, you'd need to create a wrapper that could be used:

Mustache.template = function(templateString) {
  return function() { 
    return Mustache.to_html(templateString, arguments[0], arguments[1]); 
  };
};
PackageContainer.Create()
    .TemplateFunction("Mustache.template")
    // etc...

Using Templates

Finally, the templates can be executed on the client to produce HTML. Accessing individual templates is done via their path (without the file extension):

var movies = [
  { Name: "The Matrix", ReleaseYear: 1999 },
  { Name: "Fargo", ReleaseYear: 1996 },
  { Name: "The Godfather", ReleaseYear: 1972 }
];

var htmlMovies = JST["views/templates/movies"](movies);
$(document.body).append(htmlMovies);

Redundant Prefixes

When each template shares a common prefix, it is trimmed:

PackageContainer.Create()
    .JavaScript("core", new[]
    {
        "views/templates/movies.jst",
        "views/templates/music.jst",
        "views/templates/tv.jst"
    })
    // etc...

Becomes:

JST["movies"]
JST["music"]
JST["tv"]

Template Name Casing

It may be desired that your template names use a custom casing/format (perhaps to match JavaScript naming conventions). For example, you may prefer that all of your template names have camelCase rather than PascalCase. This can be controlled via the TemplateNameCasing(Func<string, string> casing) method on the PackageContainer. Some pre-defined casings are Casing.Underscore, Casing.Lowercase and Casing.CamelCase.