Template7
Template7 is a mobile-first JavaScript template engine with Handlebars-like syntax. It is used as default template engine in Framework7
It is ultra lightweight (around 1KB minified and gzipped) and blazing fast (up to 2-3 times faster than Handlebars in mobile Safari).
Download and install Template7
First of all we need to download required Template7 files:
- We can download them from Template7 GitHub repository
- Or we can install them via Bower, enter in terminal:
$ bower install template7
In the downloaded/installed package we need JavaScript files (.js) from the dist/ folder.
And include required script in our HTML page:
<html>
<head>
...
<script src="path/to/template7.min.js"></script>
</head>
<body>
...
</body>
</html>
Templates
Template7 templates looks like Handlebars templates, it is like regular HTML but with embedded handlebars expressions:
<div class="list-block">
<ul>
{{#each items}}
<li class="item-content">
<div class="item-inner">
<div class="item-title">{{title}}</div>
</div>
</li>
{{/each}}
</ul>
</div>
Expressions syntax
Template7 support expressions with the following syntax:
Variables:
-
{{title}}
- plain variable. Outputs "title" variable in current context -
{{../title}}
- plain variable. Outputs "title" variable in parent context -
{{../../title}}
- plain variable. Outputs "title" variable in parent context of parent context -
{{this}}
- plain variable. Outputs variable equals to current context -
{{person.name}}
- plain variable. Outputs variable equals to "name" property of "person" variable in current context -
{{../person.name}}
- plain variable. The same but for parent context -
{{@index}}
- access to additional data variable. Such data variables could be used in helpers
Block expressions
-
{{#each}}
- begin of block expression -
{{else}}
- begin of block inverse expression (where supported) -
{{/each}}
- end of block expression -
{{#each reverse="true"}}
- begin of block expression with passedreverse:true
hash arguments
Helpers
Helpers could be plain expressions and block expressions:
-
{{join myArray delimiter=", "}}
- execute "join" helper and pass there "myArray" variable of current context anddelimiter:', '
hash argument
Compilation and Rendering
Template7 is a globally available Window function.
First of all we need to deliver string template. For example, we can store in script tag:
<script id="template" type="text/template7">
<p>Hello, my name is {{firstName}} {{lastName}}</p>
</script>
Now we need to compile it in JavaScript. Template7 will convert our template string to plain JavaScript function:
var template = $$('#template').html();
// compile it with Template7
var compiledTemplate = Template7.compile(template);
// Now we may render our compiled template by passing required context
var context = {
firstName: 'John',
lastName: 'Doe'
};
var html = compiledTemplate(context);
Now, html
variable will contain:
<p>Hello, my name is John Doe</p>
Built-In Helpers
Helpers in Template7 are like predefined functions that do something with passed context.
{{#each}}...{{else}}...{{/each}}
{{#each}}
is a block expression, that iterates through items of passed Array or through properties of passed Object.
The following additional variables are available inside of this helper:
-
@index
- index number of the item. For arrays only -
@first
- equal to true for the first item in array. For arrays only -
@last
- equal to true for the last item in array. For arrays only -
@key
- name of current object property. For objects only
Template -> | Context -> | Output | Iterate through Array items |
---|---|---|
|
|
|
|
|
|
Iterate through Object properties |
|
|
|
{{else}} expression. |
|
|
|
|
|
|
{{#if}}...{{else}}...{{/if}}
{{#if}} helper renders content if passed context is not "false" (or "undefined" or "null" or "" or "0") , otherwise it renders inverse content that optionally could be passed to {{else}} expression inside of helper:
Template -> | Context -> | Output |
---|---|---|
|
|
|
{{else}} expression. |
|
|
|
{{#unless}}...{{else}}...{{/unless}}
{{#unless}} helper renders content if passed context is "false" (or "undefined" or "null" or "" or "0") , otherwise it renders inverse content that optionally could be passed to {{else}} expression inside of helper:
Template -> | Context -> | Output |
---|---|---|
|
|
|
{{else}} expression. |
|
|
|
{{#with}}...{{/with}}
{{#with}} helper changes rendering context to the passed context:
Template -> | Context -> | Output |
---|---|---|
|
|
|
{{#variableName}}...{{/variableName}}
If you pass a block expression with helper name that is in the expression context, then it will work like {{#each}} helper for this context if it is an Array, and will work like {{#with}} helper if it is an Object:
Template -> | Context -> | Output |
---|---|---|
|
|
|
|
|
|
{{join delimiter=""}}
This plain helper will join Array items to single string with passed delimiter
Template -> | Context -> | Output |
---|---|---|
|
|
|
{{escape}}
This plain helper returns escaped HTML string. It escapes only the following characters: < > " &
Template -> | Context -> | Output |
---|---|---|
|
|
|
{{js "expression"}}
This inline helper allows to execute some simple JavaScript directly in template to modify/check context on the fly or for some JS calculations
Template -> | Context -> | Output |
---|---|---|
|
|
|
{{#js_if "expression"}}...{{/js_if}}
Block helper for easier compares of context variables. It renders content if JavaScript expression is not "false" (or "undefined" or "null" or "" or "0") , otherwise it renders inverse content that optionally could be passed to {{else}} expression inside of helper
Template -> | Context -> | Output |
---|---|---|
|
|
|
|
|
|
Nore that in js and in js_if helper you may need to use this.variableName
instead of just variableName
Using Custom Helpers
Template7 allows to register custom helpers with the following method:
Template7.registerHelper(name, helper)
- name -string - helper name
- helper -function - helper function to handle passed context
Helper function could accepts as many arguments as required, arguments could be context, strings and hash data.
Let's look how to register helper on example of simple {{#if}} helper:
Template7.registerHelper('if', function (condition, options) {
// "this" in function context is equal to the expression execution context
// "condition" argument contains passed context/condition
/*
@options contains object with the wollowing properties and methods:
"hash" - contains passed hash object with parameters
"fn" - method to pass helper block content further to compilier
"inverse" - method to pass helper block inverse ({{else}}) content further to compilier
"data" - contains additional expression data, like @index for arrays or @key for object
*/
// First we need to check is the passed context is function
if (typeof condition === 'function') condition = condition.call(this);
// If context condition
if (condition) {
// We need to pass block content further to compilier with the same context and the same data:
options.fn(this, options.data);
}
else {
// We need to pass block inverse ({{else}}) content further to compilier with the same context and the same data:
options.inverse(this, options.data);
}
});
Or on example of plain {{join}} helper:
Template7.registerHelper('join', function (arr, options) {
// First we need to check is the passed arr argument is function
if (typeof arr === 'function') arr = arr.call(this);
/*
Passed delimiter is in the options.hash object:
console.log(options.hash) -> {delimiter: ', '}
*/
// And return joined array
return arr.join(options.hash.delimiter);
});
Or we can create helper to create Framework7's list-block link to work with this syntax:
{{link url title target="_blank"}}
Template7.registerHelper('link', function (url, title, options){
var ret = '<li>' +
'<a href="' + url + '" class="item-content item-link" target="' + options.hash.target + '">' +
'<div class="item-inner">' +
'<div class="item-title">' + title + '</div>' +
'</div>' +
'</a>' +
'</li>';
return ret;
});
Template -> | Context -> | Output |
---|---|---|
|
|
|
Note, that all custom helpers should be registered before you compile templates with these helpers!
Remove Custom Helpers
Template7 allows to remove custom helpers with the following method:
Template7.unregisterHelper(name)
- name -string - helper name
Global Context
Template7 also supports global context which is accessible from any context.
We can specify it in Template7.global
property:
Template7.global = {
os: 'iOS',
browser: 'Chrome',
username: 'johndoe',
email: '[email protected]'
};
To access it in templates we need to use {{@global}}
variable:
<p>Hello, {{@global.username}}. Your email is {{@global.email}}</p>
Access To Root Context
Sometimes we may need to access to initially passed root context in our templates. For this case we need to use {{@root}}
variable. This is especially helpful when we are deep in context:
{
persons: [
{
name: 'John',
hobby: ['Cars', 'Food']
},
{
name: 'Kyle',
hobby: ['Travel', 'Puzzles']
},
],
showHobby: true
}
{{#each persons}}
<h2>{{name}}</h2>
<h3>Hobby:</h3>
{{#if @root.showHobby}}
<ul>
{{#each hobby}}
<li>{{this}}</li>
{{/each}}
</ul>
{{/if}}
{{/each}}
Partials
Template7 allows to reuse template using through partials. Partials are normal usual Template7 templates that may be called by other templates.
We can register and unregister partials using the following methods:
Template7.registerPartial(name, template)- register partial
- name -string - partial name
- helper -string - partial template
Template7.unregisterPartial(name)- unregister partial
- name -string - partial name
Then we can use our partials using special helper {{> "partialName"}}
Template:
<ul class="users">
{{#each users}}
{{> "user"}}
{{/each}}
</ul>
<ul class="admins">
{{#each admins}}
{{> "user"}}
{{/each}}
</ul>
Register partial:
Template7.registerPartial('user', '<li><h2>{{firstName}} {{lastName}}</h2><p>{{bio}}</p></li>')
Apply to the template this context:
{
users: [
{
firstName: 'John',
lastName: 'Doe',
bio: 'Lorem ipsum dolor'
},
{
firstName: 'Jane',
lastName: 'Doe',
bio: 'Donec sodales euismod augue'
}
],
admins: [
{
firstName: 'Mike',
lastName: 'Doe',
bio: 'Lorem ipsum dolor'
},
{
firstName: 'Kate',
lastName: 'Doe',
bio: 'Donec sodales euismod augue'
}
]
}
And we will get the following output:
<ul class="users">
<li>
<h2>John Doe</h2>
<p>Lorem ipsum dolor</p>
</li>
<li>
<h2>Jane Doe</h2>
<p>Donec sodales euismod augue</p>
</li>
</ul>
<ul class="admins">
<li>
<h2>Mike Doe</h2>
<p>Lorem ipsum dolor</p>
</li>
<li>
<h2>Kate Doe</h2>
<p>Donec sodales euismod augue</p>
</li>
</ul>
Recursive Partials
We can even use partials to make recursive templates, like nested comments:
// Simple template with just a partial
var template = '{{> "comments"}}'
// Register partial
Template7.registerPartial(
'comments',
'<ul>' +
'{{#each comments}}' +
'<li>' +
'<h2>{{author}}</h2>' +
'<p>{{text}}</p>' +
'{{#if comments}}{{> "comments"}}{{/if}}' +
'</li>' +
'{{/each}}' +
'</ul>'
);
// Compile template
var compiledTemplate = Template7.compile(template);
// Render template
var output = compiledTemplate({
comments: [
{
author: 'John Doe',
text: 'Lorem ipsum dolor',
comments: [
{
author: 'Mike Doe',
text: 'Aliquam erat volutpat'
},
{
author: 'Kate Doe',
text: 'Donec eget fringilla turpis'
}
]
},
{
author: 'Jane Doe',
text: 'Donec sodales euismod augue'
}
]
})
And the output will be:
<ul class="comments">
<li>
<h2>John Doe</h2>
<p>Lorem ipsum dolor</p>
<ul class="comments">
<li>
<h2>Mike Doe</h2>
<p>Aliquam erat volutpat</p>
</li>
<li>
<h2>Kate Doe</h2>
<p>Donec eget fringilla turpis</p>
</li>
</ul>
</li>
<li>
<h2>Jane Doe</h2>
<p>Donec sodales euismod augue</p>
</li>
</ul>
Performance Tips
Template7 is fast and you can make it even faster in your apps. The slowest part (but still very fast in T7) in compilation/rendering process is the compilation from string to pure JS function when you do Template7.compile()
. So don't compile the same templates multiple times, one time will be enough:
// Begin of your app
// Compile templates once on app load/init
var searchTemplate = $('script#search-template').html();
var compiledSearchTemplate = Template7.compile(searchTemplate);
var listTemplate = $('script#list-template').html();
var compiledListTemplate = Template7.compile(listTemplate);
// That is all, now and further just execute compiled templates with required context
// Just execute compiled search template with required content:
var html = compiledSearchTemplate({/*...some data...*/});
// Do something with html...