Scope and Context
Every part of a stache template is rendered with a
given scope. The scope is used to lookup
values. A scope can contain multiple places to lookup values. Each of those
places is called a context
.
This is very similar to how last
is looked up in the following JavaScript:
var message = "Hello"
function outer(){
var last = "Abril";
function inner(){
var first = "Alexis";
console.log(message + " "+ first + " " + last);
}
inner();
}
outer();
JavaScript looks for last
in the inner
context and then walks up the
scope to the outer
context to find a last
variable.
Let’s look at what happens with the scope the following example:
<!-- Template -->
<h1>{{message}} {{#person}}{{first}} {{last}}{{/person}}</h1>
/* Data */
{
person: { first: "Alexis" },
last: "Abril",
message: "Hello"
}
<!-- Result -->
<h1>Hello Alexis Abril</h1>
- The template is rendered with
Data
as the only item in the scope.scope:[Data]
{{message}}
is looked up withinData
.{{#person}}
adds theperson
context to the top of the scope.scope:[Data,Data.person]
{{first}}
is looked up in the scope. It will be found onData.person
.{{last}}
is looked up in the scope.last
is looked inData.person
, it’s not found.last
is looked up inData
and returned.
{{/person}}
removesperson
from the scope.scope:[Data]
The context used to lookup a value can be controlled with adding ../
or ./
before a
key. For instance, if we wanted to make sure last
was only going to lookup on person
,
we could change the template to:
<!-- Template -->
<h1>{{message}} {{#person}}{{first}} {{./last}}{{/person}}</h1>
/* Data */
{
person: { first: "Alexis" },
last: "Abril",
message: "Hello"
}
<!-- Result -->
<h1>Hello Alexis</h1>
Sections, Helpers, and custom elements can modify the scope used to render a subsection.
key modifiers like ../
and @key
can control the context and value that
gets returned.
Preventing Scope Walking
In order to prevent walking up the scope, you can explicitly choose the context a value is read from.
As mentioned above, you can explicitly read from the current context using ./
before the key:
<!-- Template -->
<h1>{{message}} {{#person}}{{first}} {{./last}}{{/person}}</h1>
/* Data */
{
person: { first: "Alexis" },
last: "Abril",
message: "Hello"
}
<!-- Result -->
<h1>Hello Alexis</h1>
You can also explicitly read from the parent context using ../
:
<!-- Template -->
<h1>{{#person}}{{../message}} {{first}}{{/person}}</h1>
/* Data */
{
person: { first: "Alexis", message: "Hello" },
message: "Hi"
}
<!-- Result -->
<h1>Hi Alexis</h1>
You can also create unique scope variables using Hash Expressions.
In the {{#each}} helper:
{{#each(todos, todo=value num=index)}}
<li data-index="{{num}}">{{todo.name}}</li>
{{/each}}
…and the {{#with}} helper:
{{#with(street=person.address.street city=person.address.city)}}
Street: {{street}}
City: {{city}}
{{/with}}
You can also always read from the root scope using scope.root
. This allows you to read data from the context you passed to your renderer function even in loops or recursive templates:
<span>{{scope.root.message}}{{name}}</span>
{{#./child}}
<div>
{{>*self}}
</div>
{{/child}}