JavaScript Templates - TheCloudlessSky/Ignite GitHub Wiki
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.
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...
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"]
.
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...
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);
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"]
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
.