Introduction
Mustache is a logic-less templating system. A Mustache template is a text string containing text and tags that represent data. The Mustache rendering engine takes a template and substitutes the tags with the data from a given data context. Although Mustache type templates are used in some JavaScript libraries such as AngularJS, they are useful by themselves. For instance they are great for processing data from an AJAX JSON call. Once the JSON data is received then the data can be passed to the Mustache engine as the context for a template. The results from the rendering engine can then be assigned to the innerHTML property of a DOM element.
Background
The mustache template system for JavaScript and it's documentation is on GitHub at https://github.com/janl/mustache.js. All of the mustache versions for different languages are at https://mustache.github.io. A similar templating system is Handlebars which is at http://handlebarsjs.com
Template Definition
A template string is pretty simple. It is a text string containing any text and mustache tags denoted by {{expression}} where expression is basically a simple JavaScript expression. The mustache compiler takes the template string and a JavaScript object and substitutes the tags with data from the object. For example a template string like "Album: {{title}}
" with a context data object: {title:"Blue Train"}
would result in the text string "Album: Blue Train". This then could be put into a web page by assigning to the innerHTML property of a DOM object. The template string can contain HTML tags and so when the compiler renders the string you get a chunk of HTML markup that can be inserted into a web page. This makes for a convenient way to dynamically change a web page, say from an AJAX call.
Basic Tags
The mustache tags {{ }}
surround an expression that references data in the supplied context object. The properties of the context data object are referenced by name. Standard Javascript dot notation is used for objects in the context.
For the most simple context object the following code:
Context = {
title:"Sketches of Spain",
artist:"Miles Davis"
};
Template = "Title: {{title}} Artist: {{artist}}";
Result = Mustache.render(Template, Context);
results in:
Title: Sketches of Spain Artist: Miles Davis
If the data contains HTML markup then use {{{ }}}
, otherwise the markup will be escaped:
Context = {
title:"<u>Miles Davis With Sonny Rollins</u>",
artist:"Miles Davis"
};
Template = "Title: {{{title}}} Artist: {{artist}}";
Result = Mustache.render(Template, Context);
which results in:
Title: <u>Miles Davis With Sonny Rollins</u> Artist: Miles Davis
If the context contains an object then use JavaScript dot notation. In the following the title and artist are fields in album so the dot notation is used in the tag:
Context = {
album: {
title:"Blue Train",
artist:"John Coltrane"
}
};
Template = "Title: {{album.title}} Artist: {{album.artist}}";
Result = Mustache.render(Template, Context);
this results in:
Title: Blue Train Artist: John Coltrane
The values undefined, null, false, or "" are not rendered. So in the following title and artist tags are not rendered:
Context = {
title:null
};
Template = "Album: Title:{{title}} Artist:{{artist}}";
document.getElementById("emptyvalue").innerHTML = Mustache.render(Template, Context);
which results in:
Album: Title: Artist:
An object in the context can be used as a "new" default context by using section tags. A section is created with the {{#section}}
tag and ended with the {{/section}}
tag. Within the section the names refer to the object named in the tag. This is similar to the using or with statement that is used in many programming languages. For the following the album object is used as the section:
Context = {
album: {
title:"The Healer",
artist: "John Lee Hooker"
}
};
Template = "{{#album}}Title: {{title}} Artist:{{artist}}{{/album}}";
Result = Mustache.render(Template, Context);
which results in:
Title: The Healer Artist: John Lee Hooker
Although Mustache templates don't have an if then statement it is still possible to specify text to display if a value doesn't exist. This is done with the {{^section}}
tag. This section is ended with the {{/section}}
tag. The following template displays the text "unknown" if the title or artist is missing:
Context = {
title:"Ball n Chain"
};
Template = "Title:{{title}}{{^title}}Unknown{{/title}} Artist:{{artist}}{{^artist}}Unknown{{/artist}}";
Result = Mustache.render(Template, Context);
this results in:
Title:Ball n Chain Artist:Unknown
Repeated Values
Although Mustache doesn't have loops, sections can serve a similar purpose. If the section name is an array then the content of the section is rendered for each value of the array. For arrays of simple data types the elements of the array are referenced with a dot. The section is not rendered if the array is empty. In the following the albums array is rendered by a section:
Context = {
albums: ["Little Creatures","Stop Making Sense"]
};
Template = "{{#albums}}<li>{{.}}</li>{{/albums}}";
Result = Mustache.render(Template, Context);
this results in
<li>Little Creatures</li><li>Stop Making Sense</li>
If the array elements are objects then the property names are used:
Context = {
albums: [{title:"Go Bo Diddley"},{title:"Have Guitar Will Travel"}]
};
Template = "{{#albums}}<li>{{title}}</li>{{/albums}}";
Result = Mustache.render(Template, Context);
which results in
<li>Go Bo Diddley</li><li>Have Guitar Will Travel</li>
Context Functions
Context objects can contain functions. They are referenced by the function name without the ()
. For a simple function:
Context = {
description: function() {
return "Transformer - Lou Reed";
}
};
Template = "{{description}}";
Result = Mustache.render(Template, Context);
this results in
Transformer - Lou Reed
Within a function this refers to the current section being rendered. In the description function the this refers to each element of the albums array:
Context = {
albums: [{title: "Foggy Mountain Jamboree", artist: "The Foggy Mountain Boys"},{title:"Country Music", artist: "The Foggy Mountain Boys"}],
description: function() {
return this.title + " - " + this.artist;
}
};
Template = "{{#albums}}<li>{{description}}</li>{{/albums}}";
Result = Mustache.render(Template,Context );
which results in
<li>Foggy Mountain Jamboree - The Foggy Mountain Boys</li><li>Country Music - The Foggy Mountain Boys</li>
Section Functions
Section names can be functions. This allows dynamically altering the rendered result. When a section function is encountered the function is called with two arguments. The first argument is the section contents and the second is a mustache rendering function. The rendering function can be used to render the the section contents. The context for the rendering function is the context that contains the section function. The return value is the rendered result. The simplest use is a function that alters the rendered result: (notice that the under function is a function that returns the actual section function)
Context = {
title:"Where Did Our Love Go",
artist: "The Supremes",
under: function() {
return function (TemplateText, MustacheRender) {
return "<u>" + MustacheRender(TemplateText) + "</u>";
};
}
};
Template = "{{#under}}{{title}}-{{artist}}{{/under}}";
Result = Mustache.render(Template,Context );
which results in
<u>Where Did Our Love Go-The Supremes</u>
The function can be used inside of an array section so the the rendered text can be tested for each element of the array. In the following code the supremes section function underlines any Supremes album:
Context = {
supremes: function() {
return function (TemplateText, MustacheRender) {
var rendered = MustacheRender(TemplateText);
if (rendered.indexOf("Supremes") >= 0)
return "<u>" + rendered + "</u>";
else
return rendered;
};
},
albums: [{title: "I Hear a Symphony", artist: "The Supremes"},{title:"The Four Tops", artist: "The Four Tops"}]
};
Template = "{{#albums}}<li>{{#supremes}}{{title}}-{{artist}}{{/supremes}}</li>{{/albums}}";
Result = Mustache.render(Template,Context );
resulting in
<li><u>I Hear a Symphony-The Supremes</u></li><li>The Four Tops-The Four Tops</li>
Order of Evaluation
The order of evaluation of context names is a little tricky. The names in a tag are evaluated starting with the inner most context. If a name is not found there then the parent context is checked and on up until the name is found. In the following title is in the albums array but artist is in the parent context:
Context = {
artist: "Neil Young",
albums: [{title: "Comes a Time"},{title: "After the Gold Rush"}]
};
Template = "{{#albums}}<li>{{title}} - {{artist}}</li>{{/albums}}";
Result = Mustache.render(Template,Context );
resulting in
<li>Comes a Time - Neil Young</li><li>After the Gold Rush - Neil Young</li>
If a function and a property have the same name then the function is called and the property is ignored.
Context = {
description: "Comes a Time - Neil Young",
description: function() {return "Harvest - Neil Young";}
};
Template = "{{description}}";
Result = Mustache.render(Template,Context );
Results in
Harvest - Neil Young
Partial Templates
Partial templates are a way to use a template in another template, sort of like an include directive. They are referenced by the {{> template}}
tag and they inherit the context of the calling template. The partial templates are passed to the render function in an object. The field names in the object are the names of the partial templates. The following code has a partial template called FancyTitle which applies a red color to the album title:
Context = {
albums: [{title: "The Four Seasons", artist: "The Four Seasons"},{title:"Hal Miller and the Rays", artist: "The Four Seasons"}],
};
var PartialTemplates = {
FancyTitle : "<span style='color:red'>{{title}}</span>"
};
Template = "{{#albums}}<div>{{> FancyTitle}} {{artist}}</div>{{/albums}}";
Result = Mustache.render(Template,Context,PartialTemplates);
this results in:
<div><span style='color:red'>The Four Seasons</span> The Four Seasons</div><div><span style='color:red'>Hal Miller and the Rays</span> The Four Seasons</div>
Using the Mustache functions
The render function parses the template and stores the parsed version in an internal cache. If the render function sees the template again it uses the cached version. The parse function causes the engine to parse and cache the template without rendering.
Mustache.parse(Template);
document.getElementById("functionvproperty").innerHTML = Mustache.render(Template,Context );