mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
New and improved Spacebars README.md
This commit is contained in:
@@ -1,140 +0,0 @@
|
||||
TODO: Merge with syntax.md
|
||||
|
||||
# Spacebars
|
||||
|
||||
Spacebars is a Meteor template language inspired by [Handlebars](http://handlebarsjs.com/). It shares much of the spirit and syntax of Handlebars, but it's tailored to produce specifications of reactive Meteor UI components when compiled.
|
||||
|
||||
NOTE: This is the eventual spec that will be supported by this branch. It's not fully implemented yet.
|
||||
|
||||
## Syntax
|
||||
|
||||
A Spacebars template consists of HTML interspersed with "stache tags" (so-called because a curly brace `{` looks a bit like a mustache). A stache tag starts with `{{` or `{{{` and ends with the same number of curly braces. Any amount of whitespace is allowed inside the curly braces at the beginning or end of a stache tag, and if there is initial puncutation such as `>` or `#` in `{{>foo}}` or `{{#foo}}`, any amount of whitespace is allowed on either side of the punctuation.
|
||||
|
||||
### Types of Tags
|
||||
|
||||
#### Double-stache
|
||||
|
||||
A basic double-stache tag consists of an identifier or a dotted path (see Paths below) and evaluates to some text:
|
||||
|
||||
```
|
||||
<h1>{{title}}</h1>
|
||||
|
||||
<p class="content {{para.class}}">
|
||||
{{para.text}}
|
||||
</p>
|
||||
```
|
||||
|
||||
Double-stache tags may only be used at the level of HTML elements (that is, outside HTML tag angle brackets) or in an attribute of an HTML tag. The inserted text is automatically HTML-escaped as appropriate (for example, turning `<` into `<`). Double-stache tags may not be used to generate the name of a tag (as in `<{{foo}}>`) or any other piece of a tag except for attribute names and values as described here.
|
||||
|
||||
Any part of an attribute name or value is fair game:
|
||||
|
||||
```
|
||||
<div data-{{foo}}={{bar}}>
|
||||
<input type="checkbox" {{isChecked}}>
|
||||
</div>
|
||||
```
|
||||
|
||||
If you want to insert multiple `name=value` pairs or a reactively changing set of attributes, use a triple-stache tag as described below.
|
||||
|
||||
If two attributes with the same name are specified using any combination of mechanisms, the resulting behavior is undefined.
|
||||
|
||||
Like most tag types, double-stache tags can take any combination of positional and keyword arguments, which themselves may contain dotted paths and literal values, as in: `{{foo bar.baz x=3 y=n type="awesome"}}`. See Tag Arguments.
|
||||
|
||||
#### Triple-stache
|
||||
|
||||
Triple-stache tags are used to insert raw HTML into a template:
|
||||
|
||||
```
|
||||
<div class="snippet">
|
||||
{{{snippetBody}}}
|
||||
</div>
|
||||
```
|
||||
|
||||
The inserted HTML must consist of balanced HTML tags, or else balanced tags with some end tags omitted per the rules of HTML parsing. You can't, for example, insert `"</div><div>"` to close an existing div and open a new one. In this form, the tag must occur at HTML element level (not inside any angle brackets).
|
||||
|
||||
A second form of the triple-stache is used inside HTML tags to insert zero or more dynamically generated attributes:
|
||||
|
||||
```
|
||||
<input type="text" {{{myAttrs}}} class="foo">
|
||||
```
|
||||
|
||||
In this form, the stache tag must occur by itself as shown and not as part of a `name=value` pair. The value of `myAttrs` may either be a string that parses as zero or more attributes, such as `""` or `"foo=bar id='myInput'"`, or an object whose property values are strings that serves as a name/value dictionary. If two attributes with the same name are specified using any combination of mechanisms, the resulting behavior is undefined.
|
||||
|
||||
#### Blocks and Inclusions
|
||||
|
||||
An inclusion tag inserts a Meteor UI component at the current element-level location in the HTML:
|
||||
|
||||
```
|
||||
<div>
|
||||
{{> thumbnail currentPhoto}}
|
||||
</div>
|
||||
```
|
||||
|
||||
A block tag also inserts a Meteor UI component, but it provides a block of content as a sort of extra argument, and an optional second block of content if the special tag `{{else}}` is used. The control structures `if` and `each` are implemented as components:
|
||||
|
||||
```
|
||||
{{#each items}}
|
||||
<div class="item">
|
||||
{{#if editing}}
|
||||
{{> editor}}
|
||||
{{else}}
|
||||
{{> itemView}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
```
|
||||
|
||||
Blocks have an open stache tag `{{#foo}}` and a corresponding close stache tag `{{/foo}}`. The template code in the block may be invoked any number of times or not at all by the component.
|
||||
|
||||
Inclusion tags and open block tags take any number of keyword arguments and one, optional positional argument that is equivalent to the `data` keyword argument (so we could have written `{{#each data=items}}` in the above example).
|
||||
|
||||
#### Comment
|
||||
|
||||
A comment begins with `{{!` and can contain any characters except for `}}`. Comments are removed upon compilation and never appear in the compiled template code or the generated HTML.
|
||||
|
||||
```
|
||||
{{! TODO: use fancy HTML5 tags}}
|
||||
<div class="section">
|
||||
...
|
||||
</div>
|
||||
```
|
||||
|
||||
### Paths
|
||||
|
||||
A "dotted path" is generally a series of one or more JavaScript identifier names separated by a dot and is used as the name of a stache tag or the value of a tag argument:
|
||||
|
||||
```
|
||||
{{> users.UserIcon contacts.current type=IconTypes.SMALL}}
|
||||
```
|
||||
|
||||
The use of `/` as a separator instead of `.` is also allowed, as in `foo/bar`.
|
||||
|
||||
An "anchored path" is one that has the identifier `this` or the special path elements `.` or `..` in the first position, as in `this.foo` or `./foo`, which are equivalent. `..` is a special path element that can appear multiple times but not after any non-`..` elements. After `this`, `.`, or a series of `..`, `this` is considered a normal identifier with no special meaning and `.` or '..` are disallowed.
|
||||
|
||||
A path element may also be written in square brackets, in which case it may contain any character except for `]`. Such an element may even be empty, written as `[]`, but the first element of a path may not be empty. Brackets are required to use one of the following as the first element of a path: `else`, `this`, `true`, `false`, and `null`. Brackets are not required around JavaScript keywords and reserved words like `var` and `for`.
|
||||
|
||||
Representationally, a path is just an array of one or more strings, where the first string may not be empty but may be a special element corresponding to `this`.
|
||||
|
||||
### Tag Arguments
|
||||
|
||||
Double-stache, triple-stache, inclusion, and (open) block tags all take positional and keyword arguments:
|
||||
|
||||
```
|
||||
{{foo bar.baz x=3 y=n type="awesome"}}
|
||||
```
|
||||
|
||||
A keyword argument looks like a positional argument prefixed with a JavaScript identifier name and an `=` character, with optional whitespace around the `=`.
|
||||
|
||||
A positional argument takes one of the following forms:
|
||||
|
||||
* A path, as described in the section "Paths"
|
||||
|
||||
* A single- or double-quoted JavaScript string literal. The string may span multiple lines if newlines are escaped, per the ECMAScript spec 5th edition.
|
||||
|
||||
* A JavaScript number literal, which may have an exponent (`1e3`) or be in hex (`0xa`).
|
||||
|
||||
* The string `true`, `false`, or `null`.
|
||||
|
||||
## Semantics
|
||||
|
||||
XXX
|
||||
@@ -1,108 +0,0 @@
|
||||
# Meteor Template Syntax Guide
|
||||
|
||||
## HTML Syntax
|
||||
|
||||
Meteor templates are written in [standard HTML](http://developers.whatwg.org/syntax.html) with some additional syntax.
|
||||
|
||||
Meteor validates your HTML as it goes and is not as lenient as a web browser, which will typically bend over backwards to recover from even wildly malformed markup. Meteor will throw a compile-time error if you violate basic HTML syntax in a way that prevents Meteor from determining the structure of your code.
|
||||
|
||||
You must close your element tags, with a few exceptions:
|
||||
|
||||
* The well-known BR, HR, IMG, and INPUT tags, along with a few others, have no end tag. You can write them in self-closing style if you like (`<br/>`) or simply write the start tag (`<br>`).
|
||||
|
||||
* You can omit the end tag of certain elements, like P and LI, according to the spec, but Meteor doesn't currently implement this feature.
|
||||
|
||||
## Template Tag Basics
|
||||
|
||||
Template tags let you insert text or other content in certain places in the HTML. Meteor calculates the current value of the template tag and automatically keeps that part of the HTML up-to-date. Template tags can only be used in the places described below. They can't be used to insert arbitrary snippets of HTML such as just an HTML start tag or just the name of a tag.
|
||||
|
||||
### Template Tags in Element Positions
|
||||
|
||||
Anywhere you could write an HTML start tag, you can use any of the five major template tag types:
|
||||
|
||||
```
|
||||
{{doubleBrace}}
|
||||
|
||||
{{{tripleBrace}}}
|
||||
|
||||
{{> inclusion}}
|
||||
|
||||
{{#block}}
|
||||
<p>Hello</p>
|
||||
{{/block}}
|
||||
|
||||
{{! This is a comment}}
|
||||
```
|
||||
|
||||
The double-brace tag `{{foo}}` is used to insert text, while the triple-brace `{{{foo}}}` is used to insert HTML. Inclusion tags like `{{> foo}}` are used to insert other templates.
|
||||
|
||||
The contents of a block `{{#foo}}...{{/foo}}` must contain balanced HTML tags! Block tags take a block of template code as input and are often used as control structures.
|
||||
|
||||
A block tag can optionally take "else content" as well:
|
||||
|
||||
```
|
||||
{{#if something}}
|
||||
<p>It's true</p>
|
||||
{{else}}
|
||||
<p>It's false</p>
|
||||
{{/if}}
|
||||
```
|
||||
|
||||
Template tags may have dotted names and take positional and keyword arguments, as in `{{foo.bar this.baz x=3 label="stuff"}}`. For more on their form and interpretation, see later sections below.
|
||||
|
||||
### Template Tags in Attribute Values
|
||||
|
||||
You can use double-braces, blocks, and comments inside an attribute value of an HTML start tag. The attribute value is the part that comes after the `=` sign, and it may be surrounded in quotes or not:
|
||||
|
||||
```
|
||||
<div class="{{myClass1}} {{myClass2}}">...</div>
|
||||
|
||||
<a href=http://{{server}}/{{path}}>...</a>
|
||||
|
||||
<input type=text value={{this.name}}>
|
||||
```
|
||||
|
||||
Using a template tag never requires additional quotes, because each template tag is parsed as a single token during HTML parsing (as if it were, say, a letter A, regardless of what it evaluates to at runtime).
|
||||
|
||||
If you use a block inside an attribute value, the block contents are parsed with the same restrictions as an attribute value. That is, you can't have HTML elements, and you can only use the template tags that are allowed in an attribute value.
|
||||
|
||||
```
|
||||
<div class="{{#if done}}done{{else}}notdone{{/if}}">...</div>
|
||||
```
|
||||
|
||||
XXX not implemented yet
|
||||
|
||||
Comment tags (`{{! This is a comment}}`) are allowed in attribute values. Triple-brace and inclusions are not allowed.
|
||||
|
||||
### Dynamic Attributes
|
||||
|
||||
As a special form, a double-brace tag can be used inside an HTML start tag to specify an arbitrary, reactively changing set of attributes:
|
||||
|
||||
```
|
||||
<div {{attrs}}>...</div>
|
||||
|
||||
<input type=checkbox {{isChecked}}>
|
||||
```
|
||||
|
||||
The tag must evaluate to an object that serves as a dictionary of attribute name and value strings. (XXX not fully implemented) For convenience, the value may also be a string or null.
|
||||
|
||||
Null or an empty string expands to `{}`. A non-empty string value must be an attribute name, which is expanded to an empty attribute. For example, `"checked"` is expanded to `{checked: ""}` (which, as far as HTML is concerned, means the checkbox is checked; the value of the attribute is ignored as long as it is present).
|
||||
|
||||
To summarize:
|
||||
|
||||
|Return Value|Equivalent HTML|
|
||||
|------------|---------------|
|
||||
|`""` or `null` or `{}`| |
|
||||
|`"checked"` or `{checked: ""}`|`checked`|
|
||||
|`{checked: "", 'class': "foo"}`|`checked class=foo`|
|
||||
|`"checked class=foo"`|ERROR, string is not an attribute name|
|
||||
|
||||
You can combine multiple dynamic attributes tags with other attributes:
|
||||
|
||||
```
|
||||
<div id=foo class={{myClass}} {{attrs1}} {{attrs2}}>...</div>
|
||||
```
|
||||
|
||||
Attributes from dynamic attribute tags are combined from left to right, after normal attributes, with later attribute values overwriting previous ones. Multiple values for the same attribute are not merged in any way, so if `attrs1` specifies a value for the `class` attribute, it will overwrite `{{myClass}}`. Meteor takes care of recalculating the element's attributes if any of `myClass`, `attrs1`, or `attrs2` changes reactively.
|
||||
|
||||
Comment tags are allowed in the reactive attribute position.
|
||||
333
packages/spacebars/README.md
Normal file
333
packages/spacebars/README.md
Normal file
@@ -0,0 +1,333 @@
|
||||
# Spacebars
|
||||
|
||||
Spacebars is a Meteor template language inspired by [Handlebars](http://handlebarsjs.com/). It shares some of the spirit and syntax of Handlebars, but it has been tailored to produce reactive Meteor templates when compiled.
|
||||
|
||||
## Getting Started
|
||||
|
||||
A Spacebars template consists of HTML interspersed with template tags, which are delimited by `{{` and `}}` (two curly braces).
|
||||
|
||||
```
|
||||
<h1>{{pageTitle}}</h1>
|
||||
|
||||
{{> nav}}
|
||||
|
||||
{{#each posts}}
|
||||
<div class="post">
|
||||
<h3>{{title}}</h3>
|
||||
<div class="post-content">
|
||||
{{{content}}}
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
```
|
||||
|
||||
As illustrated by the above example, there are four major types of template tags:
|
||||
|
||||
* `{{pageTitle}}` - Double-braced template tags are used to insert a string of text. The text is automatically made safe. It may contain any characters (like `<`) and will never produce HTML tags.
|
||||
|
||||
* `{{> nav}}` - Inclusion template tags are used to insert another template by name.
|
||||
|
||||
* `{{#each}}` - Block template tags are notable for having a block of content. The block tags `#if`, `#each`, `#with`, and `#unless` are built in, and it is also possible define custom ones. Some block tags, like `#each` and `#with`, establish a new data context for evaluating their contents. In the above example, `{{title}}` and `{{content}}` most likely refer to properties of the current post (though they could also refer to template helpers).
|
||||
|
||||
* `{{{content}}}` - Triple-braced template tags are used to insert raw HTML. Be careful with these! It's your job to make sure the HTML is safe, either by generating it yourself or sanitizing it if it came from a user input.
|
||||
|
||||
## Reactivity Model
|
||||
|
||||
Spacebars templates update reactively at a fine-grained level in response to changing data.
|
||||
|
||||
Each template tag's DOM is updated automatically when it evaluates to a new value, while avoiding unnecessary re-rendering as much as possible. For example, a double-braced tag replace its text node when its text value changes. An `#if` re-renders its contents only when the condition changes from truthy to falsy or vice versa.
|
||||
|
||||
## Identifiers and Paths
|
||||
|
||||
A Spacebars identifier is either a JavaScript identifier name or any string enclosed in square brackets (`[` and `]`). There are also the special identifiers `this` (or equivalently, `.`) and `..`. Brackets are required to use one of the following as the first element of a path: `else`, `this`, `true`, `false`, and `null`. Brackets are not required around JavaScript keywords and reserved words like `var` and `for`.
|
||||
|
||||
A Spacebars path is a series of one or more identifiers separated by either `.` or `/`, such as `foo`, `foo.bar`, `this.name`, `../title`, or `foo.[0]`.
|
||||
|
||||
### Name Resolution
|
||||
|
||||
The first identifier in a path is resolved in one of two ways:
|
||||
|
||||
* Indexing the current data context. The identifier `foo` refers to the `foo` property of the current data context object.
|
||||
|
||||
* As a template helper. The identifier `foo` refers to a helper function (or constant value) that is accessible from the current template.
|
||||
|
||||
Template helpers take priority over properties of the data context.
|
||||
|
||||
If a path starts with `..`, then the *enclosing* data context is used instead of the current one. The enclosing data context might be the one outside the current `#each`, `#with`, or template inclusion.
|
||||
|
||||
### Path Evaluation
|
||||
|
||||
When evaluating a path, identifiers after the first are used to index into the object so far, like JavaScript's `.`. However, an error is never thrown when trying to index into a non-object or an undefined value.
|
||||
|
||||
In addition, Spacebars will call functions for you, so `{{foo.bar}}` may be taken to mean `foo().bar`, `foo.bar()`, or `foo().bar()` as appropriate.
|
||||
|
||||
## Helper Arguments
|
||||
|
||||
An argument to a helper can be any path or identifier, or a string, boolean, or number literal, or null.
|
||||
|
||||
Double-braced and triple-braced template tags take any number of positional and keyword arguments:
|
||||
|
||||
```
|
||||
{{frob a b c verily=true}}
|
||||
|
||||
calls: frob(a, b, c, Spacebars.kw({verily: true}))
|
||||
```
|
||||
|
||||
`Spacebars.kw` constructs an object that is `instanceof Spacebars.kw` and whose `.hash` property is equal to its argument.
|
||||
|
||||
The helper's implementation can access the current data context as `this`.
|
||||
|
||||
## Inclusion and Block Arguments
|
||||
|
||||
Inclusion tags (`{{> foo}}`) and block tags (`{{#foo}}`) take a single
|
||||
data argument, or no argument. Any other form of arguments will be interpreted as an *object specification* or a *nested helper*:
|
||||
|
||||
* **Object specification**: If there are only keyword arguments, as in `{{#with x=1 y=2}}` or `{{> prettyBox color=red}}`, the keyword arguments will be assembled into a data object with properties named after the keywords.
|
||||
|
||||
* **Nested Helper**: If there is a positional argument followed by other (positional or keyword arguments), the first argument is called on the others using the normal helper argument calling convention.
|
||||
|
||||
## Template Tag Placement Limitations
|
||||
|
||||
Unlike purely string-based template systems, Spacebars is HTML-aware and designed to update the DOM automatically. As a result, you can't use a template tag to insert strings of HTML that don't stand on their own, such as a lone HTML start tag or end tag, or that can't be easily modified, such as the name of an HTML element.
|
||||
|
||||
There are three main locations in the HTML where template tags are allowed:
|
||||
|
||||
* At element level (i.e. anywhere an HTML tag could go)
|
||||
* In an attribute value
|
||||
* In a start tag in place of an attribute name/value pair
|
||||
|
||||
The behavior of a template tag is affected by where it is located in the HTML, and not all tags are allowed at all locations.
|
||||
|
||||
## Double-braced Tags
|
||||
|
||||
A double-braced tag at element level or in an attribute value typically evalutes to a string. If it evalutes to something else, the value will be cast to a string, unless the value is `null`, `undefined`, or `false`, which results in nothing being displayed.
|
||||
|
||||
Values returned from helpers must be pure text, not HTML. (That is, strings should have `<`, not `<`.) Spacebars will perform any necessary escaping if a template is rendered to HTML.
|
||||
|
||||
### SafeString
|
||||
|
||||
If a double-braced tag at element level evalutes to an object created with `Spacebars.SafeString("<span>Some HTML</span>")`, the HTML is inserted at the current location. The code that calls `SafeString` is asserting that this HTML is safe to insert.
|
||||
|
||||
### In Attribute Values
|
||||
|
||||
A double-braced tag may be part of, or all of, an HTML attribute value:
|
||||
|
||||
```
|
||||
<input type="checkbox" class="checky {{moreClasses}}" checked={{isChecked}}>
|
||||
```
|
||||
|
||||
An attribute value that consists entirely of template tags that return `null`, `undefined`, or `false` is considered absent; otherwise, the attribute is considered present, even if its value is empty.
|
||||
|
||||
### Dynamic Attributes
|
||||
|
||||
A double-braced tag can be used in an HTML start tag to specify an arbitrary set of attributes:
|
||||
|
||||
```
|
||||
<div {{attrs}}>...</div>
|
||||
|
||||
<input type=checkbox {{isChecked}}>
|
||||
```
|
||||
|
||||
The tag must evaluate to an object that serves as a dictionary of attribute name and value strings. For convenience, the value may also be a string or null. An empty string or null expands to `{}`. A non-empty string must be an attribute name, and expands to an attribute with an empty value; for example, `"checked"` expands to `{checked: ""}` (which, as far as HTML is concerned, means the checkbox is checked).
|
||||
|
||||
To summarize:
|
||||
|
||||
|Return Value|Equivalent HTML|
|
||||
|------------|---------------|
|
||||
|`""` or `null` or `{}`| |
|
||||
|`"checked"` or `{checked: ""}`|`checked`|
|
||||
|`{checked: "", 'class': "foo"}`|`checked class=foo`|
|
||||
|`"checked class=foo"`|ERROR, string is not an attribute name|
|
||||
|
||||
You can combine multiple dynamic attributes tags with other attributes:
|
||||
|
||||
```
|
||||
<div id=foo class={{myClass}} {{attrs1}} {{attrs2}}>...</div>
|
||||
```
|
||||
|
||||
Attributes from dynamic attribute tags are combined from left to right, after normal attributes, with later attribute values overwriting previous ones. Multiple values for the same attribute are not merged in any way, so if `attrs1` specifies a value for the `class` attribute, it will overwrite `{{myClass}}`. As always, Spacebars takes care of recalculating the element's attributes if any of `myClass`, `attrs1`, or `attrs2` changes reactively.
|
||||
|
||||
|
||||
## Triple-braced Tags
|
||||
|
||||
Triple-braced tags are used to insert raw HTML into a template:
|
||||
|
||||
```
|
||||
<div class="snippet">
|
||||
{{{snippetBody}}}
|
||||
</div>
|
||||
```
|
||||
|
||||
The inserted HTML must consist of balanced HTML tags. You can't, for example, insert `"</div><div>"` to close an existing div and open a new one.
|
||||
|
||||
This template tag cannot be used in attributes or in an HTML start tag.
|
||||
|
||||
## Inclusion Tags
|
||||
|
||||
An inclusion tag takes the form `{{> templateName}}` or `{{> templateName dataObj}}`. Other argument forms are syntactic sugar for constructing a data object (see Inclusion and Block Arguments).
|
||||
|
||||
An inclusion tag inserts an instantiation of the given template at the current location. If there is an argument, it becomes the data context, much as if the following code were used:
|
||||
|
||||
```
|
||||
{{#with dataObj}}
|
||||
{{> templateName}}
|
||||
{{/with}}
|
||||
```
|
||||
|
||||
Instead of simply naming a template, an inclusion tag can also specify a path that evalutes to a template object, or to a function that returns a template object.
|
||||
|
||||
### Function Returning a Template
|
||||
|
||||
If an inclusion tag resolves to a function, the function must return a template object or `null`. The function is reactively re-run, and if its return value changes, the template will be replaced.
|
||||
|
||||
## Block Tags
|
||||
|
||||
Block tags invoke built-in directives or custom block helpers, passing a block of template content that may be instantiated once, more than once, or not at all by the directive or helper.
|
||||
|
||||
```
|
||||
{{#block}}
|
||||
<p>Hello</p>
|
||||
{{/block}}
|
||||
```
|
||||
|
||||
Block tags may also have specify "else" content, separated from the main content by the special template tag `{{else}}`.
|
||||
|
||||
A block tag's content must consist of HTML with balanced tags.
|
||||
|
||||
Block tags can be used inside attribute values:
|
||||
|
||||
```
|
||||
<div class="{{#if done}}done{{else}}notdone{{/if}}">
|
||||
...
|
||||
</div>
|
||||
```
|
||||
|
||||
## If/Unless
|
||||
|
||||
An `#if` template tag renders either its main content or its "else" content, depending on the value of its data argument. Any falsy JavaScript value (including `null`, `undefined`, `0`, `""`, and `false`) is considered false, as well as the empty array, while any other value is considered true.
|
||||
|
||||
```
|
||||
{{#if something}}
|
||||
<p>It's true</p>
|
||||
{{else}}
|
||||
<p>It's false</p>
|
||||
{{/if}}
|
||||
```
|
||||
|
||||
`#unless` is just `#if` with the condition inverted.
|
||||
|
||||
## With
|
||||
|
||||
A `#with` template tag establishes a new data context object for its contents. The properties of the data context object are where Spacebars looks when resolving template tag names.
|
||||
|
||||
```
|
||||
{{#with employee}}
|
||||
<div>Name: {{name}}</div>
|
||||
<div>Age: {{age}}</div>
|
||||
{{/with}}
|
||||
```
|
||||
|
||||
We can take advantage of the object specification form of a block tag to define an object with properties we name:
|
||||
|
||||
```
|
||||
{{#with x=1 y=2}}
|
||||
{{{getHTMLForPoint this}}}
|
||||
{{/with}}
|
||||
```
|
||||
|
||||
If the argument to `#with` is falsy (by the same rules as for `#if`), the content is not rendered. An "else" block may be provided, which will be rendered instead.
|
||||
|
||||
If the argument to `#with` is a string or other non-object value, it may be promoted to a JavaScript wrapper object (also known as a boxed value) when passed to helpers, because JavaScript traditionally only allows an object for `this`. Use `String(this)` to get an unboxed string value or `Number(this)` to get an unboxed number value.
|
||||
|
||||
## Each
|
||||
|
||||
An `#each` template tag takes a sequence argument and inserts its content for each item in the sequence, setting the data context to the value of that item:
|
||||
|
||||
```
|
||||
<ul>
|
||||
{{#each people}}
|
||||
<li>{{name}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
```
|
||||
|
||||
The argument is typically a Meteor cursor (the result of `collection.find()`, for example), but it may also be a plain JavaScript array, `null`, or `undefined`.
|
||||
|
||||
An "else" section may be provided, which is used (with no new data
|
||||
context) if there are zero items in the sequence at any time.
|
||||
|
||||
### Reactivity Model
|
||||
|
||||
When the argument to `#each` changes, the DOM is always updated to reflect the new sequence, but it's sometimes significant exactly how that is achieved. When the argument is a Meteor live cursor, the `#each` has access to fine-grained updates to the sequence -- add, remove, move, and change callbacks -- and the items are all documents identified by unique ids. As long as the cursor itself remains constant (i.e. the query doesn't change), it is very easy to reason about how the DOM will be updated as the contents of the cursor change. The rendered content for each document persists as long as the document is in the cursor, and when documents are re-ordered, the DOM is re-ordered.
|
||||
|
||||
Things are more complicated if the argument to the `#each` reactively changes between different cursor objects, or between arrays of plain JavaScript objects that may not be identified clearly. The implementation of `#each` tries to be intelligent without doing too much expensive work.
|
||||
|
||||
XXX explain more
|
||||
|
||||
## Custom Block Helpers
|
||||
|
||||
To define your own block helper, simply declare a template, and then invoke it using `{{#someTemplate}}` (block) instead of `{{> someTemplate}}` (inclusion) syntax.
|
||||
|
||||
When a template is invoked as a block helper, it can use `{{> content}}` and `{{> elseContent}}` to include the block content it was passed.
|
||||
|
||||
Here is a simple block helper that wraps its content in a div:
|
||||
|
||||
```
|
||||
<template name="note">
|
||||
<div class="note">
|
||||
{{> content}}
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
You would invoke it as:
|
||||
|
||||
```
|
||||
{{#note}}
|
||||
Any content here
|
||||
{{/note}}
|
||||
```
|
||||
|
||||
Here is an example of implementing `#unless` in terms of `#if` (ignoring for the moment that `unless` is a built-in directive):
|
||||
|
||||
```
|
||||
<template name="unless">
|
||||
{{#if this}}
|
||||
{{> elseContent}}
|
||||
{{else}}
|
||||
{{> content}}
|
||||
{{/if}}
|
||||
</template>
|
||||
```
|
||||
|
||||
Note that the argument to `#unless` (the condition) becomes the data
|
||||
context in the `unless` template and is accessed via `this`. However,
|
||||
it would not work very well if this data context was visible to
|
||||
`content`, which is supplied by the user of `unless`.
|
||||
|
||||
Therefore, when you include `{{> content}}`, Spacebars hides the data
|
||||
context of the calling template, and any data contexts established in
|
||||
the template by `#each` and `#with`. They are not visible to the
|
||||
content block, even via `..`. Put another way, it's as if the `{{>
|
||||
content}}` inclusion occurred at the location where `{{#unless}}` was
|
||||
invoked, as far as the data context stack is concerned.
|
||||
|
||||
You can pass an argument to `{{> content}}` or `{{> elseContent}}` to
|
||||
invoke it with a data context of your choice. You can also use `{{#if
|
||||
content}}` to see if the current template was invoked as a block
|
||||
helper rather than an inclusion.
|
||||
|
||||
## Comment Tags
|
||||
|
||||
Comment template tags begin with `{{!` and can contain any characters
|
||||
except for `}}`. Comments are removed upon compilation and never
|
||||
appear in the compiled template code or the generated HTML.
|
||||
|
||||
```
|
||||
{{! Start of a section}}
|
||||
<div class="section">
|
||||
...
|
||||
</div>
|
||||
```
|
||||
|
||||
Comment tags can be used wherever other template tags are allowed.
|
||||
Reference in New Issue
Block a user