Scope and Context
Every part of a stache template is rendered with a
given scope. The scope is used to lookup
values. A scope looks in a single context
by default with
methods to look up values from above.
In this example, {{last}}
has no output because the context of the {{#person}}
block doesn't contain a last
property:
<!-- Template -->
<h1>{{message}} {{#person}}{{first}} {{last}}{{/person}}</h1>
{
person: { first: "Alexis" },
last: "Abril",
message: "Hello"
}
<!-- Result -->
<h1>Hello Alexis</h1>
A scope can walk up the contexts to find the property with the scope.find(...)
method.
This is very similar to how last
is looked up in the following JavaScript:
const message = "Hello";
function outer() {
const last = "Abril";
function inner() {
const 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}} {{scope.find('last')}}{{/person}}</h1>
{
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
.- from
{{scope.find('last')}}
,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 specified with adding ../
before a
key. For instance, if we wanted to make sure last
was going to look up above person
,
we could change the template to:
<!-- Template -->
<h1>{{message}} {{#person}}{{first}} {{../last}}{{/person}}</h1>
{
person: { first: "Alexis", last: "*****" },
last: "Abril",
message: "Hello"
}
<!-- Result -->
<h1>Hello Alexis Abril</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.
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}}