{{#better_markdown}}
Templates
Meteor applications can create reactive DOM elements directly
with Meteor.ui.render
and Meteor.ui.renderList
. Templates
provide a way to simplify the process even further, allowing you to
write your HTML structure directly in HTML files.
To create a template, include a <template>
tag with
a name attribute in any HTML file, whose content is the template text.
The template will be compiled and made available as a function on
the Template
object. The function takes some JSON data
as input, and returns a DocumentFragment
. Insert the
DocumentFragment
anywhere you like — it will
automatically update itself as the data it depends on changes.
By default, you're using the popular Handlebars templating language,
with some extensions. But there is nothing Handlebar-specific in
Meteor and other templating systems will be available as
packages. For now, read up on the
Handlebars documentation.
To render the template, you simply call the function:
<!-- in myapp.html -->
<template name="hello">
<div class="greeting">Hello there, {{first}} {{last}}!</div>
</template>
// in the JavaScript console
> Template.hello({first: "Alyssa", last: "Hacker"});
=> <div class="greeting">Hello there, Alyssa Hacker!</div>
In addition to passing JSON data directly to the template function,
you can also provide data to templates by setting additional
properties on the template function.
You can pass in functions this way, and use them just like you would
use data that was passed in as JSON.
Template.players.top_10_scorers = function () {
return Users.find({}, {sort: {score: -1}, limit: 10});
};
<!-- Use it like this -->
<template name="players">
{{#each top_10_scorers}}
<div>{{name}}</div>
{{/each}}
</template>
Functions can take arguments, and they receive the current template
data in this
.
Template.players.league_is = function (league) {
return this.league === league;
};
<!-- Use it like this -->
<template name="players">
{{#each top_10_scorers}}
{{#if league_is "junior"}}
<div>Junior: {{name}}</div>
{{/if}}
{{#if league_is "senior"}}
<div>Senior: {{name}}</div>
{{/if}}
{{/each}}
</template>
Handlebars note: {{#if league_is "junior"}}
is
allowed because of a Meteor extension that allows nested helper
calls. (Both if
and league_is
are
technically helpers, and stock Handlebars only allows one helper
invocation per expression.)
You can also pass in constant data.
// Works fine with {{#each sections}}
Template.report.sections = ["Situation", "Complication", "Resolution"];
Finally, you can set the events
property of a template
function to a table of event handlers. The format is documented at
event map. The this
argument to
the event handler will be the template data.
For now, the event handler gets the template data from the top
level of the current template, not the template data from the
template context of the element that triggered the event. This will
be changing.
<!-- myapp.html -->
<template name="scores">
{{#each player}}
{{> player_score}}
{{/each}}
</template>
<template name="player_score">
<div>{{name}}: {{score}}
<span class="give_points">Give points</span>
</div>
</template>
<!-- myapp.js -->
Template.player_score.events = {
'click .give_points': function () {
Users.update({_id: this._id}, {$inc: {score: 2}});
}
};
Templates are reactive — they are automatically wrapped
in Meteor.ui.render
. So, the DOM
elements they return automatically update themselves.
<!-- in myapp.html -->
<template name="forecast">
<div>It'll be {{prediction}} tonight</div>
</template>
<!-- in myapp.js -->
// JavaScript: reactive helper function
Template.forecast.prediction = function () {
return Session.get("weather");
};
<!-- in the console -->
> Session.set("weather", "cloudy");
> var x = Template.forecast();
=> <div>It'll be cloudy tonight</div>
> document.body.appendChild(x);
> Session.set("weather", "cool and dry");
> x
=> <div>It'll be cool and dry tonight</div>
The auto-updating continues as long as the elements are on the
screen. The specific rule is: if the elements are not children
of document
when
Meteor.flush
runs, then Meteor may
stop updating them so that the browser's garbage collector can clean
them up.
{{/better_markdown}}