// deregister from some central store
GalleryTemplates = _.without(GalleryTemplates, this);
});
Template instances
A template instance object represents an occurrence of a template in the document. It can be used to access the DOM and it can be assigned properties that persist as the template is reactively updated.
Template instance objects are found as the value of this
in the
onCreated
, onRendered
, and onDestroyed
template callbacks, and as an
argument to event handlers. You can access the current template instance
from helpers using Template.instance()
.
In addition to the properties and functions described below, you can assign
additional properties of your choice to the object. Use the
onCreated
and onDestroyed
methods to add callbacks performing initialization or clean-up on the object.
You can only access findAll
, find
, firstNode
, and lastNode
from the
onRendered
callback and event handlers, not from onCreated
and
onDestroyed
, because they require the template instance to be in the DOM.
Template instance objects are instanceof Blaze.TemplateInstance
.
Client
template.findAll(selector)
Find all elements matching selector
in this template instance.
Arguments
- selector String
-
The CSS selector to match, scoped to the template contents.
template.findAll
returns an array of DOM elements matching selector
.
Client
template.$(selector)
Find all elements matching selector
in this template instance, and return them as a JQuery object.
Arguments
- selector String
-
The CSS selector to match, scoped to the template contents.
template.$
returns a jQuery object of
those same elements. jQuery objects are similar to arrays, with
additional methods defined by the jQuery library.
The template instance serves as the document root for the selector. Only elements inside the template and its sub-templates can match parts of the selector.
Client
template.find(selector)
Find one element matching selector
in this template instance.
Arguments
- selector String
-
The CSS selector to match, scoped to the template contents.
Returns one DOM element matching selector
, or null
if there are no
such elements.
The template instance serves as the document root for the selector. Only elements inside the template and its sub-templates can match parts of the selector.
Client
template.firstNode
The first top-level DOM node in this template instance.
The two nodes firstNode
and lastNode
indicate the extent of the
rendered template in the DOM. The rendered template includes these
nodes, their intervening siblings, and their descendents. These two
nodes are siblings (they have the same parent), and lastNode
comes
after firstNode
, or else they are the same node.
Client
template.lastNode
The last top-level DOM node in this template instance.
Client
template.data
The data context of this instance's latest invocation.
This property provides access to the data context at the top level of the template. It is updated each time the template is re-rendered. Access is read-only and non-reactive.
Client
template.autorun(runFunc)
A version of Tracker.autorun that is stopped when the template is destroyed.
Arguments
- runFunc Function
-
The function to run. It receives one argument: a Tracker.Computation object.
You can use this.autorun
from an onCreated
or
onRendered
callback to reactively update the DOM
or the template instance. You can use Template.currentData()
inside
of this callback to access reactive data context of the template instance.
The Computation is automatically stopped when the template is destroyed.
Alias for template.view.autorun
.
Client
template.subscribe(name, [arg1, arg2...], [options])
A version of Meteor.subscribe that is stopped when the template is destroyed.
Arguments
- name String
-
Name of the subscription. Matches the name of the server's
publish()
call. - arg1, arg2... Any
-
Optional arguments passed to publisher function on server.
Options
- onReady Function
-
Passed to
Meteor.subscribe
. - onStop Function
-
Passed to
Meteor.subscribe
. - connection DDP Connection
-
The connection on which to make the subscription.
You can use this.subscribe
from an onCreated
callback
to specify which data publications this template depends on. The subscription is
automatically stopped when the template is destroyed.
There is a complementary function Template.instance().subscriptionsReady()
which returns true when all of the subscriptions called with this.subscribe
are ready.
Inside the template's HTML, you can use the built-in helper
Template.subscriptionsReady
, which is an easy pattern for showing loading
indicators in your templates when they depend on data loaded from subscriptions.
Example:
Template.notifications.onCreated(function () {
// Use this.subscribe inside onCreated callback
this.subscribe("notifications");
});
<template name="notifications">
{{#if Template.subscriptionsReady}}
<!-- This is displayed when all data is ready. -->
{{#each notifications}}
{{> notification}}
{{/each}}
{{else}}
Loading...
{{/if}}
</template>
Another example where the subscription depends on the data context:
Template.comments.onCreated(function () {
// Use this.subscribe with the data context reactively
this.autorun(() => {
var dataContext = Template.currentData();
this.subscribe("comments", dataContext.postId);
});
});
{{#with post}}
{{> comments postId=_id}}
{{/with}}
Another example where you want to initialize a plugin when the subscription is done:
Template.listing.onRendered(function () {
var template = this;
template.subscribe('listOfThings', () => {
// Wait for the data to load using the callback
Tracker.afterFlush(() => {
// Use Tracker.afterFlush to wait for the UI to re-render
// then use highlight.js to highlight a code snippet
highlightBlock(template.find('.code'));
});
});
});
Client
template.view
The View object for this invocation of the template.
Client
Template.registerHelper(name, function)
import { Template } from 'meteor/templating'
import { Template } from 'meteor/templating'
Defines a helper function which can be used from all templates.
Arguments
- name String
-
The name of the helper function you are defining.
- function Function
-
The helper function itself.
Client
Template.instance()
import { Template } from 'meteor/templating'
import { Template } from 'meteor/templating'
The template instance corresponding to the current template helper, event handler, callback, or autorun. If there isn't one, null
.
Client
Template.currentData()
import { Template } from 'meteor/templating'
import { Template } from 'meteor/templating'
- Inside an
onCreated
,onRendered
, oronDestroyed
callback, returns the data context of the template. - Inside an event handler, returns the data context of the template on which this event handler was defined.
- Inside a helper, returns the data context of the DOM node where the helper was used.
Establishes a reactive dependency on the result.
Client
Template.parentData([numLevels])
import { Template } from 'meteor/templating'
import { Template } from 'meteor/templating'
Accesses other data contexts that enclose the current data context.
Arguments
- numLevels Integer
-
The number of levels beyond the current data context to look. Defaults to 1.
For example, Template.parentData(0)
is equivalent to Template.currentData()
. Template.parentData(2)
is equivalent to {{../..}}
in a template.
Client
Template.body
import { Template } from 'meteor/templating'
import { Template } from 'meteor/templating'
The template object representing your <body>
tag.
You can define helpers and event maps on Template.body
just like on
any Template.myTemplate
object.
Helpers on Template.body
are only available in the <body>
tags of
your app. To register a global helper, use
Template.registerHelper.
Event maps on Template.body
don't apply to elements added to the
body via Blaze.render
, jQuery, or the DOM API, or to the body element
itself. To handle events on the body, window, or document, use jQuery
or the DOM API.
Templates
{{> Template.dynamic template=template [data=data] }}
Choose a template to include dynamically, by name.
Arguments
- template String
-
The name of the template to include.
- data Object
-
Optional. The data context in which to include the template.
Template.dynamic
allows you to include a template by name, where the name
may be calculated by a helper and may change reactively. The data
argument is optional, and if it is omitted, the current data context
is used. It's also possible, to use Template.dynamic
as a block helper
({{#Template.dynamic}} ... {{/Template.dynamic}}
)
For example, if there is a template named "foo", {{> Template.dynamic
template="foo"}}
is equivalent to {{> foo}}
and
{{#Template.dynamic template="foo"}} ... {{/Template.dynamic}}
is equivalent to {{#foo}} ... {{/foo}}
.
Event Maps
An event map is an object where the properties specify a set of events to handle, and the values are the handlers for those events. The property can be in one of several forms:
- eventtype
Matches a particular type of event, such as 'click'.
- eventtype selector
Matches a particular type of event, but only when it appears on an element that matches a certain CSS selector.
- event1, event2
To handle more than one type of event with the same function, use a comma-separated list.
The handler function receives two arguments: event
, an object with
information about the event, and template
, a template
instance for the template where the handler is
defined. The handler also receives some additional context data in
this
, depending on the context of the current element handling the
event. In a template, an element's context is the
data context where that element occurs, which is set by
block helpers such as #with
and #each
.
Example:
{
// Fires when any element is clicked
'click'(event) { ... },
// Fires when any element with the 'accept' class is clicked
'click .accept'(event) { ... },
// Fires when 'accept' is clicked or focused, or a key is pressed
'click .accept, focus .accept, keypress'(event) { ... }
}
Most events bubble up the document tree from their originating
element. For example, 'click p'
catches a click anywhere in a
paragraph, even if the click originated on a link, span, or some other
element inside the paragraph. The originating element of the event
is available as the target
property, while the element that matched
the selector and is currently handling it is called currentTarget
.
{
'click p'(event) {
var paragraph = event.currentTarget; // always a P
var clickedElement = event.target; // could be the P or a child element
}
}
If a selector matches multiple elements that an event bubbles to, it
will be called multiple times, for example in the case of 'click
div'
or 'click *'
. If no selector is given, the handler
will only be called once, on the original target element.
The following properties and methods are available on the event object passed to handlers:
- type String
The event's type, such as "click", "blur" or "keypress".
- target DOM Element
The element that originated the event.
- currentTarget DOM Element
The element currently handling the event. This is the element that matched the selector in the event map. For events that bubble, it may be
target
or an ancestor oftarget
, and its value changes as the event bubbles.- which Number
For mouse events, the number of the mouse button (1=left, 2=middle, 3=right). For key events, a character or key code.
- stopPropagation()
Prevent the event from propagating (bubbling) up to other elements. Other event handlers matching the same element are still fired, in this and other event maps.
- stopImmediatePropagation()
Prevent all additional event handlers from being run on this event, including other handlers in this event map, handlers reached by bubbling, and handlers in other event maps.
- preventDefault()
Prevents the action the browser would normally take in response to this event, such as following a link or submitting a form. Further handlers are still called, but cannot reverse the effect.
- isPropagationStopped()
Returns whether
stopPropagation()
has been called for this event.- isImmediatePropagationStopped()
Returns whether
stopImmediatePropagation()
has been called for this event.- isDefaultPrevented()
Returns whether
preventDefault()
has been called for this event.
Returning false
from a handler is the same as calling
both stopImmediatePropagation
and preventDefault
on the event.
Event types and their uses include:
click
Mouse click on any element, including a link, button, form control, or div. Use
preventDefault()
to prevent a clicked link from being followed. Some ways of activating an element from the keyboard also fireclick
.dblclick
Double-click.
focus, blur
A text input field or other form control gains or loses focus. You can make any element focusable by giving it a
tabindex
property. Browsers differ on whether links, checkboxes, and radio buttons are natively focusable. These events do not bubble.change
A checkbox or radio button changes state. For text fields, use
blur
or key events to respond to changes.mouseenter, mouseleave
The pointer enters or leaves the bounds of an element. These events do not bubble.
mousedown, mouseup
The mouse button is newly down or up.
keydown, keypress, keyup
The user presses a keyboard key.
keypress
is most useful for catching typing in text fields, whilekeydown
andkeyup
can be used for arrow keys or modifier keys.
Other DOM events are available as well, but for the events above, Meteor has taken some care to ensure that they work uniformly in all browsers.
Spacebars
Spacebars is the language used to write Meteor templates. It is inspired by Handlebars. It shares some of the spirit and syntax of Handlebars, but has been tailored to produce reactive Meteor templates when compiled.
For more information about Spacebars, see the Spacebars README.
Blaze
Blaze is the package that makes reactive templates possible. You can use the Blaze API directly in order to render templates programmatically and manipulate "Views," the building blocks of reactive templates. For more information, check out the Blaze project page.
Client
Blaze.render(templateOrView, parentNode, [nextNode], [parentView])
import { Blaze } from 'meteor/blaze'
import { Blaze } from 'meteor/blaze'
Renders a template or View to DOM nodes and inserts it into the DOM, returning a rendered View which can be passed to Blaze.remove
.
Arguments
- templateOrView Blaze.Template or Blaze.View
-
The template (e.g.
Template.myTemplate
) or View object to render. If a template, a View object is constructed. If a View, it must be an unrendered View, which becomes a rendered View and is returned. - parentNode DOM Node
-
The node that will be the parent of the rendered template. It must be an Element node.
- nextNode DOM Node
-
Optional. If provided, must be a child of parentNode; the template will be inserted before this node. If not provided, the template will be inserted as the last child of parentNode.
- parentView Blaze.View
-
Optional. If provided, it will be set as the rendered View's
parentView
.
When you render a template, the callbacks added with
onCreated
are invoked immediately, before evaluating
the content of the template. The callbacks added with
onRendered
are invoked after the View is rendered and
inserted into the DOM.
The rendered template
will update reactively in response to data changes until the View is
removed using Blaze.remove
or the View's
parent element is removed by Meteor or jQuery.
If the View is removed by some other mechanism
besides Meteor or jQuery (which Meteor integrates with by default),
the View may continue to update indefinitely. Most users will not need to
manually render templates and insert them into the DOM, but if you do,
be mindful to always call Blaze.remove
when the View is
no longer needed.
Client
Blaze.renderWithData(templateOrView, data, parentNode, [nextNode], [parentView])
import { Blaze } from 'meteor/blaze'
import { Blaze } from 'meteor/blaze'
Renders a template or View to DOM nodes with a data context. Otherwise identical to Blaze.render
.
Arguments
- templateOrView Blaze.Template or Blaze.View
-
The template (e.g.
Template.myTemplate
) or View object to render. - data Object or Function
-
The data context to use, or a function returning a data context. If a function is provided, it will be reactively re-run.
- parentNode DOM Node
-
The node that will be the parent of the rendered template. It must be an Element node.
- nextNode DOM Node
-
Optional. If provided, must be a child of parentNode; the template will be inserted before this node. If not provided, the template will be inserted as the last child of parentNode.
- parentView Blaze.View
-
Optional. If provided, it will be set as the rendered View's
parentView
.
Blaze.renderWithData(Template.myTemplate, data)
is essentially the same as
Blaze.render(Blaze.With(data, function () { return Template.myTemplate; }))
.
Client
Blaze.remove(renderedView)
import { Blaze } from 'meteor/blaze'
import { Blaze } from 'meteor/blaze'
Removes a rendered View from the DOM, stopping all reactive updates and event listeners on it. Also destroys the Blaze.Template instance associated with the view.
Arguments
- renderedView Blaze.View
-
The return value from
Blaze.render
orBlaze.renderWithData
, or theview
property of a Blaze.Template instance. CallingBlaze.remove(Template.instance().view)
from within a template event handler will destroy the view as well as that template and trigger the template'sonDestroyed
handlers.
Use Blaze.remove
to remove a template or View previously inserted with
Blaze.render
, in such a way that any behaviors attached to the DOM by
Meteor are cleaned up. The rendered template or View is now considered
"destroyed", along with all nested templates and
Views. In addition, any data assigned via
jQuery to the DOM nodes is removed, as if the nodes were passed to
jQuery's $(...).remove()
.
As mentioned in Blaze.render
, it is important to "remove"
all content rendered via Blaze.render
using Blaze.remove
, unless the
parent node of renderedView
is removed by a Meteor reactive
update or with jQuery.
Blaze.remove
can be used even if the DOM nodes in question have already
been removed from the document, to tell Blaze to stop tracking and
updating these nodes.
Client
Blaze.getData([elementOrView])
import { Blaze } from 'meteor/blaze'
import { Blaze } from 'meteor/blaze'
Returns the current data context, or the data context that was used when rendering a particular DOM element or View from a Meteor template.
Arguments
- elementOrView DOM Element or Blaze.View
-
Optional. An element that was rendered by a Meteor, or a View.
Client
Blaze.toHTML(templateOrView)
import { Blaze } from 'meteor/blaze'
import { Blaze } from 'meteor/blaze'
Renders a template or View to a string of HTML.
Arguments
- templateOrView Blaze.Template or Blaze.View
-
The template (e.g.
Template.myTemplate
) or View object from which to generate HTML.
Rendering a template to HTML loses all fine-grained reactivity. The
normal way to render a template is to either include it from another
template ({{> myTemplate}}
) or render and insert it
programmatically using Blaze.render
. Only occasionally
is generating HTML useful.
Because Blaze.toHTML
returns a string, it is not able to update the DOM
in response to reactive data changes. Instead, any reactive data
changes will invalidate the current Computation if there is one
(for example, an autorun that is the caller of Blaze.toHTML
).
Client
Blaze.toHTMLWithData(templateOrView, data)
import { Blaze } from 'meteor/blaze'
import { Blaze } from 'meteor/blaze'
Renders a template or View to HTML with a data context. Otherwise identical to Blaze.toHTML
.
Arguments
- templateOrView Blaze.Template or Blaze.View
-
The template (e.g.
Template.myTemplate
) or View object from which to generate HTML. - data Object or Function
-
The data context to use, or a function returning a data context.
Client
new Blaze.View([name], renderFunction)
import { Blaze } from 'meteor/blaze'
import { Blaze } from 'meteor/blaze'
Constructor for a View, which represents a reactive region of DOM.
Arguments
- name String
-
Optional. A name for this type of View. See
view.name
. - renderFunction Function
-
A function that returns renderable content. In this function,
this
is bound to the View.
Behind every template or part of a template — a template tag, say, like {{foo}}
or {{#if}}
— is
a View object, which is a reactively updating region of DOM.
Most applications do not need to be aware of these Views, but they offer a way to understand and customize Meteor's rendering behavior for more advanced applications and packages.
You can obtain a View object by calling Blaze.render
on a
template, or by accessing template.view
on a template
instance.
At the heart of a View is an autorun that calls the View's
renderFunction
, uses the result to create DOM nodes, and replaces the
contents of the View with these new DOM nodes. A View's content may consist
of any number of consecutive DOM nodes (though if it is zero, a placeholder
node such as a comment or an empty text node is automatically supplied). Any
reactive dependency established by renderFunction
causes a full recalculation
of the View's contents when the dependency is invalidated. Templates, however,
are compiled in such a way that they do not have top-level dependencies and so
will only ever render once, while their parts may re-render many times.
When a Blaze.View
is constructed by calling the constructor, no hooks
are fired and no rendering is performed. In particular, the View is
not yet considered to be "created." Only when the View is actually
used, by a call to Blaze.render
or Blaze.toHTML
or by inclusion in
another View, is it "created," right before it is rendered for the
first time. When a View is created, its .parentView
is set if
appropriate, and then the onViewCreated
hook is fired. The term
"unrendered View" means a newly constructed View that has not been
"created" or rendered.
The "current View" is kept in Blaze.currentView
and
is set during View rendering, callbacks, autoruns, and template event
handlers. It affects calls such as Template.currentData()
.
The following properties and methods are available on Blaze.View:
- name String
The name of this type of View. View names may be used to identify particular kinds of Views in code, but more often they simply aid in debugging and comprehensibility of the View tree. Views generated by Meteor have names like "Template.foo" and "if".
- parentView View or null
The enclosing View that caused this View to be rendered, if any.
- isCreated Boolean
True if this View has been called on to be rendered by
Blaze.render
orBlaze.toHTML
or another View. Once it becomes true, never becomes false again. A "created" View's.parentView
has been set to its final value.isCreated
is set to true beforeonViewCreated
hooks are called.- isRendered Boolean
True if this View has been rendered to DOM by
Blaze.render
or by the rendering of an enclosing View. Conversion to HTML byBlaze.toHTML
doesn't count. Once true, never becomes false.- isDestroyed Boolean
True if this View has been destroyed, such as by
Blaze.remove()
or by a reactive update that removes it. A destroyed View's autoruns have been stopped, and its DOM nodes have generally been cleaned of all Meteor reactivity and possibly dismantled.- renderCount Integer
The number of times the View has been rendered, including the current time if the View is in the process of being rendered or re-rendered.
- autorun(runFunc)
Like
Tracker.autorun
, except that the autorun is automatically stopped when the View is destroyed, and the current View is always set when runningrunFunc
. There is no relationship to the View's internal autorun or render cycle. InrunFunc
, the View is bound tothis
.- onViewCreated(func)
If the View hasn't been created yet, calls
func
when the View is created. Infunc
, the View is bound tothis
.This hook is the basis for the
created
template callback.- onViewReady(func)
Calls
func
when the View is rendered and inserted into the DOM, after waiting for the end of flush time. Does not fire if the View is destroyed at any point before it would fire. May fire multiple times (if the View re-renders). Infunc
, the View is bound tothis
.This hook is the basis for the
rendered
template callback.- onViewDestroyed(func)
If the View hasn't been destroyed yet, calls
func
when the View is destroyed. A View may be destroyed without ever becoming "ready." Infunc
, the View is bound tothis
.This hook is the basis for the
destroyed
template callback.- firstNode() DOM node
The first node of the View's rendered content. Note that this may be a text node. Requires that the View be rendered. If the View rendered to zero DOM nodes, it may be a placeholder node (comment or text node). The DOM extent of a View consists of the nodes between
view.firstNode()
andview.lastNode()
, inclusive.- lastNode() DOM node
The last node of the View's rendered content.
See
firstNode()
.- template Template
For Views created by invoking templates, the original Template object. For example,
Blaze.render(Template.foo).template === Template.foo
.- templateInstance() Template instance
For Views created by invoking templates, returns the template instance object for this particular View. For example, in a
created
callback,this.view.templateInstance() === this
.Template instance objects have fields like
data
,firstNode
, andlastNode
which are not reactive and which are also not automatically kept up to date. CallingtemplateInstance()
causes these fields to be updated.
Client
Blaze.currentView
import { Blaze } from 'meteor/blaze'
import { Blaze } from 'meteor/blaze'
The View corresponding to the current template helper, event handler, callback, or autorun. If there isn't one, null
.
The "current view" is used by Template.currentData()
and
Template.instance()
to determine
the contextually relevant data context and template instance.
Client
Blaze.getView([element])
import { Blaze } from 'meteor/blaze'
import { Blaze } from 'meteor/blaze'
Gets either the current View, or the View enclosing the given DOM element.
Arguments
- element DOM Element
-
Optional. If specified, the View enclosing
element
is returned.
If you don't specify an element
, there must be a current View or an
error will be thrown. This is in contrast to
Blaze.currentView
.
Client
Blaze.With(data, contentFunc)
import { Blaze } from 'meteor/blaze'
import { Blaze } from 'meteor/blaze'
Constructs a View that renders content with a data context.
Arguments
- data Object or Function
-
An object to use as the data context, or a function returning such an object. If a function is provided, it will be reactively re-run.
- contentFunc Function
-
A Function that returns renderable content.
Returns an unrendered View object you can pass to Blaze.render
.
Unlike {{#with}}
(as used in templates), Blaze.With
has no "else" case, and
a falsy value for the data context will not prevent the content from
rendering.
Client
Blaze.If(conditionFunc, contentFunc, [elseFunc])
import { Blaze } from 'meteor/blaze'
import { Blaze } from 'meteor/blaze'
Constructs a View that renders content conditionally.
Arguments
- conditionFunc Function
-
A function to reactively re-run. Whether the result is truthy or falsy determines whether
contentFunc
orelseFunc
is shown. An empty array is considered falsy. - contentFunc Function
-
A Function that returns renderable content.
- elseFunc Function
-
Optional. A Function that returns renderable content. If no
elseFunc
is supplied, no content is shown in the "else" case.
Returns an unrendered View object you can pass to Blaze.render
.
Matches the behavior of {{#if}}
in templates.
Client
Blaze.Unless(conditionFunc, contentFunc, [elseFunc])
import { Blaze } from 'meteor/blaze'
import { Blaze } from 'meteor/blaze'
An inverted Blaze.If
.
Arguments
- conditionFunc Function
-
A function to reactively re-run. If the result is falsy,
contentFunc
is shown, otherwiseelseFunc
is shown. An empty array is considered falsy. - contentFunc Function
-
A Function that returns renderable content.
- elseFunc Function
-
Optional. A Function that returns renderable content. If no
elseFunc
is supplied, no content is shown in the "else" case.
Returns an unrendered View object you can pass to Blaze.render
.
Matches the behavior of {{#unless}}
in templates.
Client
Blaze.Each(argFunc, contentFunc, [elseFunc])
import { Blaze } from 'meteor/blaze'
import { Blaze } from 'meteor/blaze'
Constructs a View that renders contentFunc
for each item in a sequence.
Arguments
- argFunc Function
-
A function to reactively re-run. The function can return one of two options:
An object with two fields: '_variable' and '_sequence'. Each iterates over '_sequence', it may be a Cursor, an array, null, or undefined. Inside the Each body you will be able to get the current item from the sequence using the name specified in the '_variable' field.
Just a sequence (Cursor, array, null, or undefined) not wrapped into an object. Inside the Each body, the current item will be set as the data context.
- contentFunc Function
-
A Function that returns renderable content.
- elseFunc Function
-
A Function that returns renderable content to display in the case when there are no items in the sequence.
Returns an unrendered View object you can pass to Blaze.render
.
Matches the behavior of {{#each}}
in templates.
Client
new Blaze.Template([viewName], renderFunction)
import { Blaze } from 'meteor/blaze'
import { Blaze } from 'meteor/blaze'
Constructor for a Template, which is used to construct Views with particular name and content.
Arguments
- viewName String
-
Optional. A name for Views constructed by this Template. See
view.name
. - renderFunction Function
-
A function that returns renderable content. This function is used as the
renderFunction
for Views constructed by this Template.
Templates defined by the template compiler, such as Template.myTemplate
,
are objects of type Blaze.Template
(aliased as Template
).
In addition to methods like events
and helpers
, documented as part of
the Template API, the following fields and methods are
present on template objects:
- viewName String
Same as the constructor argument.
- renderFunction Function
Same as the constructor argument.
- constructView()
Constructs and returns an unrendered View object. This method is invoked by Meteor whenever the template is used, such as by
Blaze.render
or by{{> foo}}
wherefoo
resolves to a Template object.constructView()
constructs a View usingviewName
andrenderFunction
as constructor arguments, and then configures it as a template View, setting upview.template
,view.templateInstance()
, event maps, and so on.
Client
Blaze.isTemplate(value)
import { Blaze } from 'meteor/blaze'
import { Blaze } from 'meteor/blaze'
Returns true if value
is a template object like Template.myTemplate
.
Arguments
- value Any
-
The value to test.
Renderable Content
A value is renderable content if it is one of the following:
- A template object like
Template.myTemplate
- An unrendered View object, like the return value of
Blaze.With
null
orundefined
Internally, renderable content includes objects representing HTML tags as well, but these objects are not yet part of the officially-supported, public API.
Timers
Meteor uses global environment variables
to keep track of things like the current request's user. To make sure
these variables have the right values, you need to use
Meteor.setTimeout
instead of setTimeout
and Meteor.setInterval
instead of setInterval
.
These functions work just like their native JavaScript equivalents.
If you call the native function, you'll get an error stating that Meteor
code must always run within a Fiber, and advising to use
Meteor.bindEnvironment
.
Anywhere
Meteor.setTimeout(func, delay)
import { Meteor } from 'meteor/meteor'
import { Meteor } from 'meteor/meteor'
Call a function in the future after waiting for a specified delay.
Arguments
- func Function
-
The function to run
- delay Number
-
Number of milliseconds to wait before calling function
Returns a handle that can be used by Meteor.clearTimeout
.
Anywhere
Meteor.setInterval(func, delay)
import { Meteor } from 'meteor/meteor'
import { Meteor } from 'meteor/meteor'
Call a function repeatedly, with a time delay between calls.
Arguments
- func Function
-
The function to run
- delay Number
-
Number of milliseconds to wait between each function call.
Returns a handle that can be used by Meteor.clearInterval
.
Anywhere
Meteor.clearTimeout(id)
import { Meteor } from 'meteor/meteor'
import { Meteor } from 'meteor/meteor'
Cancel a function call scheduled by Meteor.setTimeout
.
Arguments
- id Number
-
The handle returned by
Meteor.setTimeout
Anywhere
Meteor.clearInterval(id)
import { Meteor } from 'meteor/meteor'
import { Meteor } from 'meteor/meteor'
Cancel a repeating function call scheduled by Meteor.setInterval
.
Arguments
- id Number
-
The handle returned by
Meteor.setInterval
Tracker
Meteor has a simple dependency tracking system which allows it to
automatically rerun templates and other computations whenever
Session
variables, database queries, and other data
sources change.
Unlike most other systems, you don't have to manually declare these dependencies — it "just works". The mechanism is simple and efficient. When you call a function that supports reactive updates (such as a database query), it automatically saves the current Computation object, if any (representing, for example, the current template being rendered). Later, when the data changes, the function can "invalidate" the Computation, causing it to rerun (rerendering the template).
Applications will find Tracker.autorun
useful, while more
advanced facilities such as Tracker.Dependency
and onInvalidate
callbacks are intended primarily for package authors implementing new
reactive data sources.
Client
Tracker.autorun(runFunc, [options])
import { Tracker } from 'meteor/tracker'
import { Tracker } from 'meteor/tracker'
Run a function now and rerun it later whenever its dependencies change. Returns a Computation object that can be used to stop or observe the rerunning.
Arguments
- runFunc Function
-
The function to run. It receives one argument: the Computation object that will be returned.
Options
- onError Function
-
Optional. The function to run when an error happens in the Computation. The only argument it recieves is the Error thrown. Defaults to the error being logged to the console.
Tracker.autorun
allows you to run a function that depends on reactive data
sources, in such a way that if there are changes to the data later,
the function will be rerun.
For example, you can monitor a cursor (which is a reactive data source) and aggregate it into a session variable:
Tracker.autorun(function () {
var oldest = _.max(Monkeys.find().fetch(), function (monkey) {
return monkey.age;
});
if (oldest)
Session.set("oldest", oldest.name);
});
Or you can wait for a session variable to have a certain value, and do
something the first time it does, calling stop
on the computation to
prevent further rerunning:
Tracker.autorun(function (c) {
if (! Session.equals("shouldAlert", true))
return;
c.stop();
alert("Oh no!");
});
The function is invoked immediately, at which point it may alert and
stop right away if shouldAlert
is already true. If not, the
function is run again when shouldAlert
becomes true.
A change to a data dependency does not cause an immediate rerun, but
rather "invalidates" the computation, causing it to rerun the next
time a flush occurs. A flush will occur automatically as soon as
the system is idle if there are invalidated computations. You can
also use Tracker.flush
to cause an immediate flush of
all pending reruns.
If you nest calls to Tracker.autorun
, then when the outer call stops or
reruns, the inner call will stop automatically. Subscriptions and
observers are also automatically stopped when used as part of a
computation that is rerun, allowing new ones to be established. See
Meteor.subscribe
for more information about
subscriptions and reactivity.
If the initial run of an autorun throws an exception, the computation is automatically stopped and won't be rerun.
Client
Tracker.flush()
import { Tracker } from 'meteor/tracker'
import { Tracker } from 'meteor/tracker'
Process all reactive updates immediately and ensure that all invalidated computations are rerun.
Normally, when you make changes (like writing to the database), their impact (like updating the DOM) is delayed until the system is idle. This keeps things predictable — you can know that the DOM won't go changing out from under your code as it runs. It's also one of the things that makes Meteor fast.
Tracker.flush
forces all of the pending reactive updates to complete.
For example, if an event handler changes a Session
variable that will cause part of the user interface to rerender, the
handler can call flush
to perform the rerender immediately and then
access the resulting DOM.
An automatic flush occurs whenever the system is idle which performs
exactly the same work as Tracker.flush
. The flushing process consists
of rerunning any invalidated computations. If additional
invalidations happen while flushing, they are processed as part of the
same flush until there is no more work to be done. Callbacks
registered with Tracker.afterFlush
are called
after processing outstanding invalidations.
It is illegal to call flush
from inside a flush
or from a running
computation.
The Meteor Manual
describes the motivation for the flush cycle and the guarantees made by
Tracker.flush
and Tracker.afterFlush
.
Client
Tracker.nonreactive(func)
import { Tracker } from 'meteor/tracker'
import { Tracker } from 'meteor/tracker'
Run a function without tracking dependencies.
Arguments
- func Function
-
A function to call immediately.
Calls func
with Tracker.currentComputation
temporarily set to null
and returns func
's own return value. If func
accesses reactive data
sources, these data sources will never cause a rerun of the enclosing
computation.
Client
Tracker.active
import { Tracker } from 'meteor/tracker'
import { Tracker } from 'meteor/tracker'
True if there is a current computation, meaning that dependencies on reactive data sources will be tracked and potentially cause the current computation to be rerun.
This value is useful for data source implementations to determine whether they are being accessed reactively or not.
Client
Tracker.currentComputation
import { Tracker } from 'meteor/tracker'
import { Tracker } from 'meteor/tracker'
The current computation, or null
if there isn't one. The current computation is the Tracker.Computation
object created by the innermost active call to Tracker.autorun
, and it's the computation that gains dependencies when reactive data sources are accessed.
It's very rare to need to access currentComputation
directly. The
current computation is used implicitly by
Tracker.active
(which tests whether there is one),
dependency.depend()
(which registers that it depends on a
dependency), and Tracker.onInvalidate
(which
registers a callback with it).
Client
Tracker.onInvalidate(callback)
import { Tracker } from 'meteor/tracker'
import { Tracker } from 'meteor/tracker'
Registers a new onInvalidate
callback on the current computation (which must exist), to be called immediately when the current computation is invalidated or stopped.
Arguments
- callback Function
-
A callback function that will be invoked as
func(c)
, wherec
is the computation on which the callback is registered.
See computation
.onInvalidate
for more
details.
Client
Tracker.afterFlush(callback)
import { Tracker } from 'meteor/tracker'
import { Tracker } from 'meteor/tracker'
Schedules a function to be called during the next flush, or later in the current flush if one is in progress, after all invalidated computations have been rerun. The function will be run once and not on subsequent flushes unless afterFlush
is called again.
Arguments
- callback Function
-
A function to call at flush time.
Functions scheduled by multiple calls to afterFlush
are guaranteed
to run in the order that afterFlush
was called. Functions are
guaranteed to be called at a time when there are no invalidated
computations that need rerunning. This means that if an afterFlush
function invalidates a computation, that computation will be rerun
before any other afterFlush
functions are called.
Tracker.Computation
A Computation object represents code that is repeatedly rerun in
response to reactive data changes. Computations don't have return
values; they just perform actions, such as rerendering a template on
the screen. Computations are created using Tracker.autorun
.
Use stop
to prevent further rerunning of a
computation.
Each time a computation runs, it may access various reactive data sources that serve as inputs to the computation, which are called its dependencies. At some future time, one of these dependencies may trigger the computation to be rerun by invalidating it. When this happens, the dependencies are cleared, and the computation is scheduled to be rerun at flush time.
The current computation
(Tracker.currentComputation
) is the
computation that is currently being run or rerun (computed), and the
one that gains a dependency when a reactive data source is accessed.
Data sources are responsible for tracking these dependencies using
Tracker.Dependency
objects.
Invalidating a computation sets its invalidated
property to true
and immediately calls all of the computation's onInvalidate
callbacks. When a flush occurs, if the computation has been invalidated
and not stopped, then the computation is rerun by setting the
invalidated
property to false
and calling the original function
that was passed to Tracker.autorun
. A flush will occur when the current
code finishes running, or sooner if Tracker.flush
is called.
Stopping a computation invalidates it (if it is valid) for the purpose of calling callbacks, but ensures that it will never be rerun.
Example:
// if we're in a computation, then perform some clean-up
// when the current computation is invalidated (rerun or
// stopped)
if (Tracker.active) {
Tracker.onInvalidate(function () {
x.destroy();
y.finalize();
});
}
Client
computation.stop()
Prevents this computation from rerunning.
Stopping a computation is irreversible and guarantees that it will never be rerun. You can stop a computation at any time, including from the computation's own run function. Stopping a computation that is already stopped has no effect.
Stopping a computation causes its onInvalidate
callbacks to run
immediately if it is not currently invalidated, as well as its
stop
callbacks.
Nested computations are stopped automatically when their enclosing computation is rerun.
Client
computation.invalidate()
Invalidates this computation so that it will be rerun.
Invalidating a computation marks it to be rerun at
flush time, at
which point the computation becomes valid again. It is rare to
invalidate a computation manually, because reactive data sources
invalidate their calling computations when they change. Reactive data
sources in turn perform this invalidation using one or more
Tracker.Dependency
objects.
Invalidating a computation immediately calls all onInvalidate
callbacks registered on it. Invalidating a computation that is
currently invalidated or is stopped has no effect. A computation can
invalidate itself, but if it continues to do so indefinitely, the
result will be an infinite loop.
Client
computation.onInvalidate(callback)
Registers callback
to run when this computation is next invalidated, or runs it immediately if the computation is already invalidated. The callback is run exactly once and not upon future invalidations unless onInvalidate
is called again after the computation becomes valid again.
Arguments
- callback Function
-
Function to be called on invalidation. Receives one argument, the computation that was invalidated.
onInvalidate
registers a one-time callback that either fires
immediately or as soon as the computation is next invalidated or
stopped. It is used by reactive data sources to clean up resources or
break dependencies when a computation is rerun or stopped.
To get a callback after a computation has been recomputed, you can
call Tracker.afterFlush
from onInvalidate
.
Client
computation.onStop(callback)
Registers callback
to run when this computation is stopped, or runs it immediately if the computation is already stopped. The callback is run after any onInvalidate
callbacks.
Arguments
- callback Function
-
Function to be called on stop. Receives one argument, the computation that was stopped.
Client
computation.stopped
True if this computation has been stopped.
Client
computation.invalidated
True if this computation has been invalidated (and not yet rerun), or if it has been stopped.
This property is initially false. It is set to true by stop()
and
invalidate()
. It is reset to false when the computation is
recomputed at flush time.
Client
computation.firstRun
True during the initial run of the computation at the time Tracker.autorun
is called, and false on subsequent reruns and at other times.
This property is a convenience to support the common pattern where a computation has logic specific to the first run.
Tracker.Dependency
A Dependency represents an atomic unit of reactive data that a computation might depend on. Reactive data sources such as Session or Minimongo internally create different Dependency objects for different pieces of data, each of which may be depended on by multiple computations. When the data changes, the computations are invalidated.
Dependencies don't store data, they just track the set of computations to invalidate if something changes. Typically, a data value will be accompanied by a Dependency object that tracks the computations that depend on it, as in this example:
var weather = "sunny";
var weatherDep = new Tracker.Dependency;
var getWeather = function () {
weatherDep.depend()
return weather;
};
var setWeather = function (w) {
weather = w;
// (could add logic here to only call changed()
// if the new value is different from the old)
weatherDep.changed();
};
This example implements a weather data source with a simple getter and
setter. The getter records that the current computation depends on
the weatherDep
dependency using depend()
, while the setter
signals the dependency to invalidate all dependent computations by
calling changed()
.
The reason Dependencies do not store data themselves is that it can be
useful to associate multiple Dependencies with the same piece of data.
For example, one Dependency might represent the result of a database
query, while another might represent just the number of documents in
the result. A Dependency could represent whether the weather is sunny
or not, or whether the temperature is above freezing.
Session.equals
is implemented this way for
efficiency. When you call Session.equals("weather", "sunny")
, the
current computation is made to depend on an internal Dependency that
does not change if the weather goes from, say, "rainy" to "cloudy".
Conceptually, the only two things a Dependency can do are gain a dependent and change.
A Dependency's dependent computations are always valid (they have
invalidated === false
). If a dependent is invalidated at any time,
either by the Dependency itself or some other way, it is immediately
removed.
See the Meteor Manual to learn how to create a reactive data source using Tracker.Dependency.
Client
dependency.changed()
Invalidate all dependent computations immediately and remove them as dependents.
Client
dependency.depend([fromComputation])
Declares that the current computation (or fromComputation
if given) depends on dependency
. The computation will be invalidated the next time dependency
changes.
If there is no current computation and depend()
is called with no arguments, it does nothing and returns false.
Returns true if the computation is a new dependent of dependency
rather than an existing one.
Arguments
- fromComputation Tracker.Computation
-
An optional computation declared to depend on
dependency
instead of the current computation.
dep.depend()
is used in reactive data source implementations to record
the fact that dep
is being accessed from the current computation.
Client
dependency.hasDependents()
True if this Dependency has one or more dependent Computations, which would be invalidated if this Dependency were to change.
For reactive data sources that create many internal Dependencies, this function is useful to determine whether a particular Dependency is still tracking any dependency relationships or if it can be cleaned up to save memory.
ReactiveVar
To use ReactiveVar
, add the reactive-var
package to your project by running
in your terminal:
meteor add reactive-var
Client
new ReactiveVar(initialValue, [equalsFunc])
import { ReactiveVar } from 'meteor/reactive-var'
import { ReactiveVar } from 'meteor/reactive-var'
Constructor for a ReactiveVar, which represents a single reactive variable.
Arguments
- initialValue Any
-
The initial value to set.
equalsFunc
is ignored when setting the initial value. - equalsFunc Function
-
Optional. A function of two arguments, called on the old value and the new value whenever the ReactiveVar is set. If it returns true, no set is performed. If omitted, the default
equalsFunc
returns true if its arguments are===
and are of type number, boolean, string, undefined, or null.
A ReactiveVar holds a single value that can be get and set, such that calling
set
will invalidate any Computations that called get
, according to the
usual contract for reactive data sources.
A ReactiveVar is similar to a Session variable, with a few differences:
ReactiveVars don't have global names, like the "foo" in
Session.get("foo")
. Instead, they may be created and used locally, for example attached to a template instance, as in:this.foo.get()
.ReactiveVars are not automatically migrated across hot code pushes, whereas Session state is.
ReactiveVars can hold any value, while Session variables are limited to JSON or EJSON.
An important property of ReactiveVars — which is sometimes a
reason for using one — is that setting the value to the same
value as before has no effect; it does not trigger any invalidations.
So if one autorun sets a ReactiveVar, and another autorun gets the
ReactiveVar, a re-run of the first autorun won't necessarily trigger
the second. By default, only primitive values are compared this way,
while calling set
on an argument that is an object (not a
primitive) always counts as a change. You can configure this behavior
using the equalsFunc
argument.
Client
reactiveVar.get()
Returns the current value of the ReactiveVar, establishing a reactive dependency.
Client
reactiveVar.set(newValue)
Sets the current value of the ReactiveVar, invalidating the Computations that called get
if newValue
is different from the old value.
Arguments
- newValue Any
EJSON
EJSON is an extension of JSON to support more types. It supports all JSON-safe types, as well as:
- Date (JavaScript
Date
) - Binary (JavaScript
Uint8Array
or the result ofEJSON.newBinary
) - User-defined types (see
EJSON.addType
. For example,Mongo.ObjectID
is implemented this way.)
All EJSON serializations are also valid JSON. For example an object with a date and a binary buffer would be serialized in EJSON as:
{
"d": {"$date":<PHONE_NUMBER>553},
"b": {"$binary": "c3VyZS4="}
}
Meteor supports all built-in EJSON data types in publishers, method arguments
and results, Mongo databases, and Session
variables.
Anywhere
EJSON.parse(str)
import { EJSON } from 'meteor/ejson'
import { EJSON } from 'meteor/ejson'
Parse a string into an EJSON value. Throws an error if the string is not valid EJSON.
Arguments
- str String
-
A string to parse into an EJSON value.
Anywhere
EJSON.stringify(val, [options])
import { EJSON } from 'meteor/ejson'
import { EJSON } from 'meteor/ejson'
Serialize a value to a string.
For EJSON values, the serialization fully represents the value. For non-EJSON values, serializes the same way as JSON.stringify
.
Arguments
- val EJSON-able Object
-
A value to stringify.
Options
- indent Boolean, Integer, or String
-
Indents objects and arrays for easy readability. When
true
, indents by 2 spaces; when an integer, indents by that number of spaces; and when a string, uses the string as the indentation pattern. - canonical Boolean
-
When
true
, stringifies keys in an object in sorted order.
Anywhere
EJSON.fromJSONValue(val)
import { EJSON } from 'meteor/ejson'
import { EJSON } from 'meteor/ejson'
Deserialize an EJSON value from its plain JSON representation.
Arguments
- val JSON-compatible Object
-
A value to deserialize into EJSON.
Anywhere
EJSON.toJSONValue(val)
import { EJSON } from 'meteor/ejson'
import { EJSON } from 'meteor/ejson'
Serialize an EJSON-compatible value into its plain JSON representation.
Arguments
- val EJSON-able Object
-
A value to serialize to plain JSON.
Anywhere
EJSON.equals(a, b, [options])
import { EJSON } from 'meteor/ejson'
import { EJSON } from 'meteor/ejson'
Return true if a
and b
are equal to each other. Return false otherwise. Uses the equals
method on a
if present, otherwise performs a deep comparison.
Arguments
Options
- keyOrderSensitive Boolean
-
Compare in key sensitive order, if supported by the JavaScript implementation. For example,
{a: 1, b: 2}
is equal to{b: 2, a: 1}
only whenkeyOrderSensitive
isfalse
. The default isfalse
.
Anywhere
EJSON.clone(val)
import { EJSON } from 'meteor/ejson'
import { EJSON } from 'meteor/ejson'
Return a deep copy of val
.
Arguments
- val EJSON-able Object
-
A value to copy.
Anywhere
EJSON.newBinary
import { EJSON } from 'meteor/ejson'
import { EJSON } from 'meteor/ejson'
Allocate a new buffer of binary data that EJSON can serialize.
Arguments
- size Number
-
The number of bytes of binary data to allocate.
Buffers of binary data are represented by Uint8Array
instances on JavaScript
platforms that support them. On implementations of JavaScript that do not
support Uint8Array
, binary data buffers are represented by standard arrays
containing numbers ranging from 0 to 255, and the $Uint8ArrayPolyfill
key
set to true
.
Anywhere
EJSON.isBinary(x)
import { EJSON } from 'meteor/ejson'
import { EJSON } from 'meteor/ejson'
Returns true if x
is a buffer of binary data, as returned from EJSON.newBinary
.
Arguments
- x Object
-
The variable to check.
Anywhere
EJSON.addType(name, factory)
import { EJSON } from 'meteor/ejson'
import { EJSON } from 'meteor/ejson'
Add a custom datatype to EJSON.
Arguments
- name String
-
A tag for your custom type; must be unique among custom data types defined in your project, and must match the result of your type's
typeName
method. - factory Function
-
A function that deserializes a JSON-compatible value into an instance of your type. This should match the serialization performed by your type's
toJSONValue
method.
When you add a type to EJSON, Meteor will be able to use that type in:
- publishing objects of your type if you pass them to publish handlers.
- allowing your type in the return values or arguments to methods.
- storing your type client-side in Minimongo.
- allowing your type in
Session
variables.
Instances of your type must implement typeName
and
toJSONValue
methods, and may implement
clone
and equals
methods if the
default implementations are not sufficient.
Anywhere
customType.typeName()
Return the tag used to identify this type. This must match the tag used to register this type with EJSON.addType
.
Anywhere
customType.toJSONValue()
Serialize this instance into a JSON-compatible value.
For example, the toJSONValue
method for
Mongo.ObjectID
could be:
function () {
return this.toHexString();
};
Anywhere
customType.clone()
Return a value r
such that this.equals(r)
is true, and modifications to r
do not affect this
and vice versa.
If your type does not have a clone
method, EJSON.clone
will use
toJSONValue
and the factory instead.
Anywhere
customType.equals(other)
Return true
if other
has a value equal to this
; false
otherwise.
Arguments
- other Object
-
Another object to compare this to.
The equals
method should define an equivalence
relation. It should have
the following properties:
- Reflexivity - for any instance
a
:a.equals(a)
must be true. - Symmetry - for any two instances
a
andb
:a.equals(b)
if and only ifb.equals(a)
. - Transitivity - for any three instances
a
,b
, andc
:a.equals(b)
andb.equals(c)
impliesa.equals(c)
.
If your type does not have an equals
method, EJSON.equals
will compare the
result of calling toJSONValue
instead.
HTTP
HTTP
provides an HTTP request API on the client and server. To use
these functions, add the HTTP package to your project by running in your
terminal:
meteor add http
Anywhere
HTTP.call(method, url, [options], [asyncCallback])
import { HTTP } from 'meteor/http'
import { HTTP } from 'meteor/http'
Perform an outbound HTTP request.
Arguments
- method String
-
The HTTP method to use, such as "
GET
", "POST
", or "HEAD
". - url String
-
The URL to retrieve.
- asyncCallback Function
-
Optional callback. If passed, the method runs asynchronously, instead of synchronously, and calls asyncCallback. On the client, this callback is required.
Options
- content String
-
String to use as the HTTP request body.
- data Object
-
JSON-able object to stringify and use as the HTTP request body. Overwrites
content
. - query String
-
Query string to go in the URL. Overwrites any query string in
url
. - params Object
-
Dictionary of request parameters to be encoded and placed in the URL (for GETs) or request body (for POSTs). If
content
ordata
is specified,params
will always be placed in the URL. - auth String
-
HTTP basic authentication string of the form
"username:password"
- headers Object
-
Dictionary of strings, headers to add to the HTTP request.
- timeout Number
-
Maximum time in milliseconds to wait for the request before failing. There is no timeout by default.
- followRedirects Boolean
-
If
true
, transparently follow HTTP redirects. Cannot be set tofalse
on the client. Defaulttrue
. - npmRequestOptions Object
-
On the server,
HTTP.call
is implemented by using the npmrequest
module. Any options in this object will be passed directly to therequest
invocation. - beforeSend Function
-
On the client, this will be called before the request is sent to allow for more direct manipulation of the underlying XMLHttpRequest object, which will be passed as the first argument. If the callback returns
false
, the request will be not be send.
This function initiates an HTTP request to a remote server.
On the server, this function can be run either synchronously or
asynchronously. If the callback is omitted, it runs synchronously
and the results are returned once the request completes successfully.
If the request was not successful, an error is thrown.
This is
useful when making server-to-server HTTP API calls from within Meteor
methods, as the method can succeed or fail based on the results of the
synchronous HTTP call. In this case, consider using
this.unblock()
to allow other methods on the same
connection to run in
the mean time. On the client, this function must be used
asynchronously by passing a callback.
Both HTTP and HTTPS protocols are supported. The url
argument must be
an absolute URL including protocol and host name on the server, but may be
relative to the current host on the client. The query
option
replaces the query string of url
. Parameters specified in params
that are put in the URL are appended to any query string.
For example, with a url
of "/path?query"
and
params
of {foo:"bar"}
, the final URL will be "/path?query&foo=bar"
.
The params
are put in the URL or the request body, depending on the
type of request. In the case of request with no bodies, like GET and
HEAD, the parameters will always go in the URL. For a POST or other
type of request, the parameters will be encoded into the body with a
standard x-www-form-urlencoded
content type, unless the content
or data
option is used to specify a body, in which case the
parameters will be appended to the URL instead.
When run in asynchronous mode, the callback receives two arguments,
error
and result
. The
error
argument will contain an Error if the request fails in any
way, including a network error, time-out, or an HTTP status code in
the 400 or 500 range. In case of a 4xx/5xx HTTP status code, the
response
property on error
matches the contents of the result
object. When run in synchronous mode, either result
is returned
from the function, or error
is thrown.
Contents of the result object:
- statusCode Number
- Numeric HTTP result status code, or
null
on error. - content String
- The body of the HTTP response as a string.
- data
Object or
null
- If the response headers indicate JSON content, this contains the body of the document parsed as a JSON object.
- headers Object
- A dictionary of HTTP headers from the response.
Example server method:
Meteor.methods({checkTwitter: function (userId) {
check(userId, String);
this.unblock();
try {
var result = HTTP.call("GET", "http://api.twitter.com/xyz",
{params: {user: userId}});
return true;
} catch (e) {
// Got a network error, time-out or HTTP error in the 400 or 500 range.
return false;
}
}});
Example asynchronous HTTP call:
HTTP.call("POST", "http://api.twitter.com/xyz",
{data: {some: "json", stuff: 1}},
function (error, result) {
if (!error) {
Session.set("twizzled", true);
}
});
Anywhere
HTTP.get(url, [callOptions], [asyncCallback])
import { HTTP } from 'meteor/http'
import { HTTP } from 'meteor/http'
Send an HTTP GET
request. Equivalent to calling HTTP.call
with "GET" as the first argument.
Arguments
- url String
-
The URL to which the request should be sent.
- callOptions Object
-
Options passed on to
HTTP.call
. - asyncCallback Function
-
Callback that is called when the request is completed. Required on the client.
Anywhere
HTTP.post(url, [callOptions], [asyncCallback])
import { HTTP } from 'meteor/http'
import { HTTP } from 'meteor/http'
Send an HTTP POST
request. Equivalent to calling HTTP.call
with "POST" as the first argument.
Arguments
- url String
-
The URL to which the request should be sent.
- callOptions Object
-
Options passed on to
HTTP.call
. - asyncCallback Function
-
Callback that is called when the request is completed. Required on the client.
Anywhere
HTTP.put(url, [callOptions], [asyncCallback])
import { HTTP } from 'meteor/http'
import { HTTP } from 'meteor/http'
Send an HTTP PUT
request. Equivalent to calling HTTP.call
with "PUT" as the first argument.
Arguments
- url String
-
The URL to which the request should be sent.
- callOptions Object
-
Options passed on to
HTTP.call
. - asyncCallback Function
-
Callback that is called when the request is completed. Required on the client.
Anywhere
HTTP.del(url, [callOptions], [asyncCallback])
import { HTTP } from 'meteor/http'
import { HTTP } from 'meteor/http'
Send an HTTP DELETE
request. Equivalent to calling HTTP.call
with "DELETE" as the first argument. (Named del
to avoid conflict with the Javascript keyword delete
)
Arguments
- url String
-
The URL to which the request should be sent.
- callOptions Object
-
Options passed on to
HTTP.call
. - asyncCallback Function
-
Callback that is called when the request is completed. Required on the client.
The email
package allows sending email from a Meteor app. To use it, add the
package to your project by running in your terminal:
meteor add email
The server reads from the MAIL_URL
environment variable to determine how to
send mail. Currently, Meteor supports sending mail over SMTP; the MAIL_URL
environment variable should be of the form
smtp://USERNAME:PASSWORD@HOST:PORT/
.
If MAIL_URL
is not set, Email.send
outputs the message to standard output
instead.
Server
Email.send(options)
import { Email } from 'meteor/email'
import { Email } from 'meteor/email'
Send an email. Throws an Error
on failure to contact mail server
or if mail server returns an error. All fields should match
RFC5322 specification.
If the MAIL_URL
environment variable is set, actually sends the email.
Otherwise, prints the contents of the email to standard out.
Note that this package is based on mailcomposer version 0.1.15
, so make
sure to refer to the documentation for that version if using the
attachments
or mailComposer
options.
Click here to read the mailcomposer 0.1.15 docs.
Options
- from String
-
"From:" address (required)
- to, cc, bcc, replyTo String or Array of Strings
-
"To:", "Cc:", "Bcc:", and "Reply-To:" addresses
- subject String
-
"Subject:" line
- text, html String
-
Mail body (in plain text and/or HTML)
- headers Object
-
Dictionary of custom headers
- attachments Array of Objects
-
Array of attachment objects, as described in the mailcomposer documentation.
- mailComposer MailComposer
-
A MailComposer object representing the message to be sent. Overrides all other options. You can access the
mailcomposer
npm module atEmailInternals.NpmModules.mailcomposer.module
.
You must provide the from
option and at least one of to
, cc
, and bcc
;
all other options are optional.
Email.send
only works on the server. Here is an example of how a
client could use a server method call to send an email. (In an actual
application, you'd need to be careful to limit the emails that a
client could send, to prevent your server from being used as a relay
by spammers.)
// In your server code: define a method that the client can call
Meteor.methods({
sendEmail: function (to, from, subject, text) {
check([to, from, subject, text], [String]);
// Let other method calls from the same client start running,
// without waiting for the email sending to complete.
this.unblock();
Email.send({
to: to,
from: from,
subject: subject,
text: text
});
}
});
// In your client code: asynchronously send an email
Meteor.call('sendEmail',
<EMAIL_ADDRESS><EMAIL_ADDRESS>'Hello from Meteor!',
'This is a test of Email.send.');
Assets
Assets
allows server code in a Meteor application to access static server
assets, which are located in the private
subdirectory of an application's
tree. Assets are not processed as source files and are copied directly
into your application's bundle.
Server
Assets.getText(assetPath, [asyncCallback])
Retrieve the contents of the static server asset as a UTF8-encoded string.
Arguments
- assetPath String
-
The path of the asset, relative to the application's
private
subdirectory. - asyncCallback Function
-
Optional callback, which is called asynchronously with the error or result after the function is complete. If not provided, the function runs synchronously.
Server
Assets.getBinary(assetPath, [asyncCallback])
Retrieve the contents of the static server asset as an EJSON Binary.
Arguments
- assetPath String
-
The path of the asset, relative to the application's
private
subdirectory. - asyncCallback Function
-
Optional callback, which is called asynchronously with the error or result after the function is complete. If not provided, the function runs synchronously.
Static server assets are included by placing them in the application's private
subdirectory. For example, if an application's private
subdirectory includes a
directory called nested
with a file called data.txt
inside it, then server
code can read data.txt
by running:
var data = Assets.getText('nested/data.txt');
Note: Packages can only access their own assets. If you need to read the assets of a different package, or of the enclosing app, you need to get a reference to that package's Assets
object.
Package.js
A package is a directory containing a package.js file, which contains roughly three major sections: a basic description, a package definition, and a test definition. By default, the directory name is the name of the package.
The package.js
file below is an example of how to use the packaging API. The
rest of this section will explain the specific API commands in greater detail.
/* Information about this package */
Package.describe({
// Short two-sentence summary.
summary: "What this does",
// Version number.
version: "1.0.0",
// Optional. Default is package directory name.
name: "username:package-name",
// Optional github URL to your source repository.
git: "https://github.com/something/something.git",
});
/* This defines your actual package */
Package.onUse(function (api) {
// If no version is specified for an 'api.use' dependency, use the
// one defined in Meteor 0.9.0.
api.versionsFrom('0.9.0');
// Use Underscore package, but only on the server.
// Version not specified, so it will be as of Meteor 0.9.0.
api.use('underscore', 'server');
// Use iron:router package, version 1.0.0 or newer.
api.use('iron:router@1.0.0');
// Give users of this package access to the Templating package.
api.imply('templating')
// Export the object 'Email' to packages or apps that use this package.
api.export('Email', 'server');
// Specify the source code for the package.
api.addFiles('email.js', 'server');
});
/* This defines the tests for the package */
Package.onTest(function (api) {
// Sets up a dependency on this package
api.use('username:package-name');
// Allows you to use the 'tinytest' framework
api.use('tinytest@1.0.0');
// Specify the source code for the package tests
api.addFiles('email_tests.js', 'server');
});
/* This lets you use npm packages in your package*/
Npm.depends({
simplesmtp: "0.3.10",
"stream-buffers": "0.2.5"});
Build plugins are created with
Package.registerBuildPlugin
. See the
coffeescript package for an example. Build plugins are fully-fledged Meteor
programs in their own right and have their own namespace, package dependencies,
source files and npm requirements.
You can use local packages to define custom build plugins for your app, with one caveat. In published packages, build plugins are already bundled with their transitive dependencies. So if you want a dependency of a build plugin to be satisfied by a local package, you must use a local copy of the package that defines the plugin (even if you make no changes to that package) so that Meteor will pick up the local dependency.
Package Description
Provide basic package information with Package.describe(options)
. To publish a
package, you must define summary
and version
.
package.js
Package.describe(options)
Provide basic package information.
Options
- summary String
-
A concise 1-2 sentence description of the package, required for publication.
- version String
-
The (extended) semver version for your package. Additionally, Meteor allows a wrap number: a positive integer that follows the version number. If you are porting another package that uses semver versioning, you may want to use the original version, postfixed with
_wrapnumber
. For example,1.2.3_1
or2.4.5-rc1_4
. Wrap numbers sort after the original numbers:1.2.3
<1.2.3_1
<1.2.3_2
<1.2.4-rc.0
. If no version is specified, this field defaults to0.0.0
. If you want to publish your package to the package server, you must specify a version. - name String
-
Optional name override. By default, the package name comes from the name of its directory.
- git String
-
Optional Git URL to the source repository.
- documentation String
-
Optional Filepath to documentation. Set to 'README.md' by default. Set this to null to submit no documentation.
- debugOnly Boolean
-
A package with this flag set to true will not be bundled into production builds. This is useful for packages meant to be used in development only.
- prodOnly Boolean
-
A package with this flag set to true will ONLY be bundled into production builds.
- testOnly Boolean
-
A package with this flag set to true will ONLY be bundled as part of
meteor test
.
Package Definition
Define dependencies and expose package methods with the
Package.onUse
handler. This section lets you define what packages your package
depends on, what packages are implied by your package, and what object your
package is exported to.
package.js
Package.onUse(func)
Define package dependencies and expose package methods.
Arguments
- func Function
-
A function that takes in the package control
api
object, which keeps track of dependencies and exports.
package.js
api.versionsFrom(meteorRelease)
Use versions of core packages from a release. Unless provided,
all packages will default to the versions released along with
meteorRelease
. This will save you from having to figure out the exact
versions of the core packages you want to use. For example, if the newest
release of meteor is<EMAIL_ADDRESS>and it includes<EMAIL_ADDRESS>, you
can write<EMAIL_ADDRESS>in your package, and when you
later write api.use('jquery')
, it will be equivalent to
<EMAIL_ADDRESS>. You may specify an array of multiple releases,
in which case the default value for constraints will be the "or" of the
versions from each release<EMAIL_ADDRESS><EMAIL_ADDRESS>may cause api.use('jquery')
to be interpreted as
<EMAIL_ADDRESS>|| 2.0.0')
.
Arguments
- meteorRelease String or Array of Strings
-
Specification of a release: track@version. Just 'version' (e.g.
"0.9.0"
) is sufficient if using the default release trackMETEOR
. Can be an array of specifications.
package.js
api.use(packageNames, [architecture], [options])
Depend on package packagename
.
Arguments
- packageNames String or Array of Strings
-
Packages being depended on. Package names may be suffixed with an @version tag.
In general, you must specify a package's version (e.g.,
<EMAIL_ADDRESS>to use version 1.0.0 or a higher compatible version (ex: 1.0.1, 1.5.0, etc.) of theaccounts
package). If you are sourcing core packages from a Meteor release withversionsFrom
, you may leave off version names for core packages. You may also specify constraints, such<EMAIL_ADDRESS>(this package demandsmy:forms
at1.0.0
exactly<EMAIL_ADDRESS>|| =2.0.1
(my:forms
at1.x.y
, or exactly2.0.1
). - architecture String or Array of Strings
-
If you only use the package on the server (or the client), you can pass in the second argument (e.g.,
'server'
,'client'
,'web.browser'
,'web.cordova'
) to specify what architecture the package is used with. You can specify multiple architectures by passing in an array, for example['web.cordova', 'os.linux']
.
Options
- weak Boolean
-
Establish a weak dependency on a package. If package A has a weak dependency on package B, it means that including A in an app does not force B to be included too — but, if B is included or by another package, then B will load before A. You can use this to make packages that optionally integrate with or enhance other packages if those packages are present. When you weakly depend on a package you don't see its exports. You can detect if the possibly-present weakly-depended-on package is there by seeing if
Package.foo
exists, and get its exports from the same place. - unordered Boolean
-
It's okay to load this dependency after your package. (In general, dependencies specified by
api.use
are loaded before your package.) You can use this option to break circular dependencies.
package.js
api.imply(packageNames, [architecture])
Give users of this package access to another package (by passing
in the string packagename
) or a collection of packages (by passing in
an array of strings [packagename1
, packagename2
]
Arguments
- packageNames String or Array of Strings
-
Name of a package, or array of package names, with an optional @version component for each.
- architecture String or Array of Strings
-
If you only use the package on the server (or the client), you can pass in the second argument (e.g.,
'server'
,'client'
,'web.browser'
,'web.cordova'
) to specify what architecture the package is used with. You can specify multiple architectures by passing in an array, for example['web.cordova', 'os.linux']
.
package.js
api.export(exportedObjects, [architecture], [exportOptions], exportOptions.testOnly)
Export package-level variables in your package. The specified
variables (declared without var
in the source code) will be available
to packages that use your package. If your package sets the debugOnly
,
prodOnly
or testOnly
options to true
when it calls
Package.describe()
, then packages that use your package will need to use
Package["package-name"].ExportedVariableName
to access the value of an
exported variable.
Arguments
- exportedObjects String or Array of Strings
-
Name of the object to export, or an array of object names.
- architecture String or Array of Strings
-
If you only want to export the object on the server (or the client), you can pass in the second argument (e.g., 'server', 'client', 'web.browser', 'web.cordova') to specify what architecture the export is used with. You can specify multiple architectures by passing in an array, for example
['web.cordova', 'os.linux']
. - exportOptions Object
- exportOptions.testOnly Boolean
-
If true, this symbol will only be exported when running tests for this package.
package.js
api.addFiles(filenames, [architecture], [options])
Specify source code files for your package.
Arguments
- filenames String or Array of Strings
-
Paths to the source files.
- architecture String or Array of Strings
-
If you only want to use the file on the server (or the client), you can pass this argument (e.g., 'server', 'client', 'web.browser', 'web.cordova') to specify what architecture the file is used with. You can specify multiple architectures by passing in an array, for example
['web.cordova', 'os.linux']
. By default, the file will be loaded on both server and client.
Options
- bare Boolean
-
If this file is JavaScript code or will be compiled into JavaScript code by a build plugin, don't wrap the resulting file in a closure. Has the same effect as putting a file into the
client/compatibility
directory in an app.
package.js
api.addAssets(filenames, architecture)
Specify asset files for your package. They can be accessed via
the Assets API from the server, or at the URL
/packages/username_package-name/file-name
from the client, depending on the
architecture passed.
Arguments
- filenames String or Array of Strings
-
Paths to the asset files.
- architecture String or Array of Strings
-
Specify where this asset should be available (e.g., 'server', 'client', 'web.browser', 'web.cordova'). You can specify multiple architectures by passing in an array, for example
['web.cordova', 'os.linux']
.
Unit Tests
Set up your tests with the Package.onTest
handler, which has an interface
that's parallel to that of the onUse
handler. The tests will need to depend on
the package that you have just created. For example, if your package is the
email
package, you have to call api.use('email')
in order to test the
package.
If you used meteor create
to set up your package, Meteor will create the
required scaffolding in package.js
, and you'll only need to add unit test code
in the _test.js
file that was created.
package.js
Package.onTest(func)
Define dependencies and expose package methods for unit tests.
Arguments
- func Function
-
A function that takes in the package control 'api' object, which keeps track of dependencies and exports.
External Packages and Plugins
Meteor packages can include NPM packages and Cordova plugins by using
Npm.depends
and Cordova.depends
in the package.js
file.
package.js
Npm.depends(dependencies)
Specify which NPM packages your Meteor package depends on.
Arguments
- dependencies Object
-
An object where the keys are package names and the values are one of:
- Version numbers in string form
- Http(s) URLs to a git commit by SHA.
- Git URLs in the format described here
Https URL example:
Npm.depends({ moment: "2.8.3", async: "https://github.com/caolan/async/archive/71fa2638973dafd8761fa5457c472a312cc820fe.tar.gz" });
Git URL example:
Npm.depends({ moment: "2.8.3", async: "git+https://github.com/caolan/async#master" });
Server
Npm.require(name)
Require a package that was specified using
Npm.depends()
.
Arguments
- name String
-
The name of the package to require.
package.js
Cordova.depends(dependencies)
Specify which Cordova / PhoneGap plugins your Meteor package depends on.
Plugins are installed from plugins.cordova.io, so the plugins and versions specified must exist there. Alternatively, the version can be replaced with a GitHub tarball URL as described in the Cordova page of the Meteor wiki on GitHub.
Arguments
- dependencies Object
-
An object where the keys are plugin names and the values are version numbers or GitHub tarball URLs in string form. Example:
Cordova.depends({ "org.apache.cordova.camera": "0.3.0" });
Alternatively, with a GitHub URL:
Cordova.depends({ "org.apache.cordova.camera": "https://github.com/apache/cordova-plugin-camera/tarball/d84b875c449d68937520a1b352e09f6d39044fbf" });
package.js
Package.registerBuildPlugin([options])
Define a build plugin. A build plugin extends the build
process for apps and packages that use this package. For example,
the coffeescript
package uses a build plugin to compile CoffeeScript
source files into JavaScript.
Options
- name String
-
A cosmetic name, must be unique in the package.
- use String or Array of Strings
-
Meteor packages that this plugin uses, independent of the packages specified in api.onUse.
- sources Array of Strings
-
The source files that make up the build plugin, independent from api.addFiles.
- npmDependencies Object
-
An object where the keys are NPM package names, and the values are the version numbers of required NPM packages, just like in Npm.depends.
Build Plugin
Plugin.registerSourceHandler(fileExtension, handler)
Inside a build plugin source file specified in Package.registerBuildPlugin, add a handler to compile files with a certain file extension.
Arguments
- fileExtension String
-
The file extension that this plugin should handle, without the first dot. Examples:
"coffee"
,"coffee.md"
. - handler Function
-
A function that takes one argument, a CompileStep object.
Documentation for CompileStep is available on the GitHub Wiki.
Mobile Config File
If your Meteor application targets mobile platforms such as iOS or
Android, you can configure your app's metadata and build process
in a special top-level file called
mobile-config.js
which is not included in your application and is used only
for this configuration.
The code snippet below is an example mobile-config.js
file. The rest of this
section will explain the specific API commands in greater detail.
// This section sets up some basic app metadata,
// the entire section is optional.
App.info({
id: 'com.example.matt.uber',
name: 'über',
description: 'Get über power in one button click',
author: 'Matt Development Group',
email<EMAIL_ADDRESS>website: 'http://example.com'
});
// Set up resources such as icons and launch screens.
App.icons({
'iphone': 'icons/icon-60.png',
'iphone_2x'<EMAIL_ADDRESS>// ... more screen sizes and platforms ...
});
App.launchScreens({
'iphone': 'splash/Default~iphone.png',
'iphone_2x'<EMAIL_ADDRESS>// ... more screen sizes and platforms ...
});
// Set PhoneGap/Cordova preferences
App.setPreference('BackgroundColor', '0xff0000ff');
App.setPreference('HideKeyboardFormAccessoryBar', true);
App.setPreference('Orientation', 'default');
App.setPreference('Orientation', 'all', 'ios');
// Pass preferences for a particular PhoneGap/Cordova plugin
App.configurePlugin('com.phonegap.plugins.facebookconnect', {
APP_ID: '1234567890',
API_KEY: 'supersecretapikey'
});
App.info(options)
Set your mobile app's core configuration information.
Options
- id, version, name, description, author, email, website String
-
Each of the options correspond to a key in the app's core configuration as described in the Cordova documentation.
App.setPreference(name, value, [platform])
Add a preference for your build as described in the Cordova documentation.
Arguments
- name String
-
A preference name supported by Cordova's
config.xml
. - value String
-
The value for that preference.
- platform String
-
Optional. A platform name (either
ios
orandroid
) to add a platform-specific preference.
App.accessRule(pattern, [options])
Set a new access rule based on origin domain for your app. By default your application has a limited list of servers it can contact. Use this method to extend this list.
Default access rules:
tel:*
,geo:*
,mailto:*
,sms:*
,market:*
are allowed and are handled by the system (e.g. opened in the phone app or an email client)http://localhost:*
is used to serve the app's assets from.- The domain or address of the Meteor server to connect to for DDP and hot code push of new versions.
Read more about domain patterns in Cordova docs.
Starting with Meteor 1.0.4 access rule for all domains and protocols
(<access origin="*"/>
) is no longer set by default due to
certain kind of possible
attacks.
Arguments
- pattern String
-
The pattern defining affected domains or URLs.
Options
- type String
-
Possible values:
'intent'
: Controls which URLs the app is allowed to ask the system to open. (e.g. in the phone app or an email client).'navigation'
: Controls which URLs the WebView itself can be navigated to (can also needed for iframes).'network'
or undefined: Controls which network requests (images, XHRs, etc) are allowed to be made.
- launchExternal Boolean
-
(Deprecated, use
type: 'intent'
instead.)
App.configurePlugin(id, config)
Set the build-time configuration for a Cordova plugin.
Arguments
- id String
-
The identifier of the plugin you want to configure.
- config Object
-
A set of key-value pairs which will be passed at build-time to configure the specified plugin.
App.icons(icons)
Set the icons for your mobile app.
Arguments
- icons Object
-
An Object where the keys are different devices and screen sizes, and values are image paths relative to the project root directory.
Valid key values:
iphone_2x
(120x120)iphone_3x
(180x180)ipad
(76x76)ipad_2x
(152x152)ipad_pro
(167x167)ios_settings
(29x29)ios_settings_2x
(58x58)ios_settings_3x
(87x87)ios_spotlight
(40x40)ios_spotlight_2x
(80x80)android_mdpi
(48x48)android_hdpi
(72x72)android_xhdpi
(96x96)android_xxhdpi
(144x144)android_xxxhdpi
(192x192)
App.launchScreens(launchScreens)
Set the launch screen images for your mobile app.
Arguments
- launchScreens Object
-
A dictionary where keys are different devices, screen sizes, and orientations, and the values are image paths relative to the project root directory.
For Android, launch screen images should be special "Nine-patch" image files that specify how they should be stretched. See the Android docs.
Valid key values:
iphone_2x
(640x960)iphone5
(640x1136)iphone6
(750x1334)iphone6p_portrait
(1242x2208)iphone6p_landscape
(2208x1242)ipad_portrait
(768x1024)ipad_portrait_2x
(1536x2048)ipad_landscape
(1024x768)ipad_landscape_2x
(2048x1536)android_mdpi_portrait
(320x470)android_mdpi_landscape
(470x320)android_hdpi_portrait
(480x640)android_hdpi_landscape
(640x480)android_xhdpi_portrait
(720x960)android_xhdpi_landscape
(960x720)android_xxhdpi_portrait
(1080x1440)android_xxhdpi_landscape
(1440x1080)
Packages
Meteor supports a variety of add-on packages and third party libraries. While you can build great applications using only the Meteor core functionality, optional packages can make development even faster and better.
Packages can be added to a Meteor project with:
meteor add <package_name>
and removed with:
meteor remove <package_name>
Some of the packages that Meteor Development Group maintains include:
appcache
The appcache
package stores the static parts of a Meteor application
(the client side Javascript, HTML, CSS, and images) in the browser's
application cache. To enable
caching simply add the appcache
package to your project.
Once a user has visited a Meteor application for the first time and the application has been cached, on subsequent visits the web page loads faster because the browser can load the application out of the cache without contacting the server first.
Hot code pushes are loaded by the browser in the background while the app continues to run. Once the new code has been fully loaded the browser is able to switch over to the new code quickly.
The application cache allows the application to be loaded even when the browser doesn't have an Internet connection, and so enables using the app offline.
(Note however that the appcache
package by itself doesn't make
data available offline: in an application loaded offline, a Meteor
Collection will appear to be empty in the client until the Internet
becomes available and the browser is able to establish a DDP
connection).
To turn AppCache off for specific browsers use:
Meteor.AppCache.config({
chrome: false,
firefox: false
});
The supported browsers that can be enabled or disabled include, but are
not limited to, android
, chrome
, chromium
, chromeMobileIOS
,
firefox
, ie
, mobileSafari
and safari
.
Browsers limit the amount of data they will put in the application cache, which can vary due to factors such as how much disk space is free. Unfortunately if your application goes over the limit rather than disabling the application cache altogether and running the application online, the browser will instead fail that particular update of the cache, leaving your users running old code.
Thus it's best to keep the size of the cache below 5MB. The
appcache
package will print a warning on the Meteor server console
if the total size of the resources being cached is over 5MB.
If you have files too large to fit in the cache you can disable caching by URL prefix. For example,
Meteor.AppCache.config({onlineOnly: ['/online/']});
causes files in your public/online
directory to not be cached, and
so they will only be available online. You can then move your large
files into that directory and refer to them at the new URL:
<img src="/online/bigimage.jpg">
If you'd prefer not to move your files, you can use the file names themselves as the URL prefix:
Meteor.AppCache.config({
onlineOnly: [
'/bigimage.jpg',
'/largedata.json'
]
});
though keep in mind that since the exclusion is by prefix (this is a
limitation of the application cache manifest), excluding
/largedata.json
will also exclude such URLs as
/largedata.json.orig
and /largedata.json/file1
.
For more information about how Meteor interacts with the application cache, see the AppCache page in the Meteor wiki.
accounts-ui
A turn-key user interface for Meteor Accounts.
To add Accounts and a set of login controls to an application, add the
accounts-ui
package and at least one login provider package:
accounts-password
, accounts-facebook
, accounts-github
,
accounts-google
, accounts-twitter
, or accounts-weibo
.
Then simply add the {{> loginButtons}}
helper to an HTML file. This
will place a login widget on the page. If there is only one provider configured
and it is an external service, this will add a login/logout button. If you use
accounts-password
or use multiple external login services, this will add
a "Sign in" link which opens a dropdown menu with login options. If you plan to
position the login dropdown in the right edge of the screen, use
{{> loginButtons align="right"}}
in order to get the dropdown to lay
itself out without expanding off the edge of the screen.
To configure the behavior of {{> loginButtons}}
, use
Accounts.ui.config
.
accounts-ui
also includes modal popup dialogs to handle links from
sendResetPasswordEmail
, sendVerificationEmail
,
and sendEnrollmentEmail
. These
do not have to be manually placed in HTML: they are automatically activated
when the URLs are loaded.
If you want to control the look and feel of your accounts system a little more, we recommend reading the useraccounts section of the Meteor Guide.
audit-argument-checks
This package causes Meteor to require that all arguments passed to methods and
publish functions are check
ed. Any method that does not pass each
one of its arguments to check
will throw an error, which will be logged on the
server and which will appear to the client as a
500 Internal server error
. This is a simple way to help ensure that your
app has complete check coverage.
Methods and publish functions that do not need to validate their arguments can
simply run check(arguments, [Match.Any])
to satisfy the
audit-argument-checks
coverage checker.
coffeescript
CoffeeScript is a little language that compiles into JavaScript. It provides a simple syntax without lots of braces and parentheses. The code compiles one-to-one into the equivalent JS, and there is no interpretation at runtime.
CoffeeScript is supported on both the client and the server. Files
ending with .coffee
, .litcoffee
, or .coffee.md
are automatically
compiled to JavaScript.
Namespacing and CoffeeScript
Here's how CoffeeScript works with Meteor's namespacing.
Per the usual CoffeeScript convention, CoffeeScript variables are file-scoped by default (visible only in the
.coffee
file where they are defined.)When writing a package, CoffeeScript-defined variables can be exported like any other variable (see Writing Packages). Exporting a variable pulls it up to package scope, meaning that it will be visible to all of the code in your app or package (both
.js
and.coffee
files).Package-scope variables declared in
.js
files are visible in any.coffee
files in the same app or project.There is no way to make a package-scope variable from a
.coffee
file other than exporting it. We couldn't figure out a way to make this fit naturally inside the CoffeeScript language. If you want to use package-scope variables with CoffeeScript, one way is to make a short.js
file that declares all of your package-scope variables. They can then be used and assigned to from.coffee
files.If you want to share variables between
.coffee
files in the same package, and don't want to separately declare them in a.js
file, we have an experimental feature that you may like. An object calledshare
is visible in CoffeeScript code and is shared across all.coffee
files in the same package. So, you can writeshare.foo
for a value that is shared between all CoffeeScript code in a package, but doesn't escape that package.
Heavy CoffeeScript users, please let us know how this arrangement
works for you, whether share
is helpful for you, and anything else
you'd like to see changed.
ecmascript
This package lets you use new JavaScript language features that are part of the ECMAScript 2015 specification but are not yet supported by all engines or browsers. Unsupported syntax is automatically translated into standard JavaScript that behaves the same way.
This video from the July 2015 Meteor Devshop gives an overview of how the package works, and what it provides.
Usage
The ecmascript
package registers a compiler plugin that transpiles
ECMAScript 2015+ to ECMAScript 5 (standard JS) in all .js
files. By
default, this package is pre-installed for all new apps and packages.
To add this package to an existing app, run the following command from your app directory:
meteor add ecmascript
To add the ecmascript
package to an existing package, include the
statement api.use('ecmascript');
in the Package.onUse
callback in your
package.js
file:
Package.onUse(function (api) {
api.use('ecmascript');
});
Supported ES2015 Features
Syntax
The ecmascript
package uses Babel to compile
ES2015 syntax to ES5 syntax. Many but not all ES2015 features can be
simulated by Babel, and ecmascript
enables most of the features
supported by Babel.
Here is a list of the Babel transformers that are currently enabled:
es3.propertyLiterals
Makes it safe to use reserved keywords likecatch
as unquoted keys in object literals. For example,{ catch: 123 }
is translated to{ "catch": 123 }
.es3.memberExpressionLiterals
Makes it safe to use reserved keywords as property names. For example,object.catch
is translated toobject["catch"]
.es6.arrowFunctions
Provides a shorthand for function expressions. For example,[1, 2, 3].map(x => x + 1)
evaluates to[2, 3, 4]
. Ifthis
is used in the body of the arrow function, it will be automatically bound to the value ofthis
in the enclosing scope.es6.literals
Adds support for binary and octal numeric literals. For example,0b111110111 === 503
and0o767 === 503
.es6.templateLiterals
Enables multi-line strings delimited by backticks instead of quotation marks, with variable interpolation:js var name = "Ben"; var message = `My name is: ${name}`;
es6.classes
Enablesclass
syntax:class Base { constructor(a, b) { this.value = a * b; } }</p> <p>class Derived extends Base { constructor(a, b) { super(a + 1, b + 1); } }</p> <p>var d = new Derived(2, 3); d.value; // 12
es6.constants
Allows defining block-scoped variables that are not allowed to be redefined:const GOLDEN_RATIO = (1 + Math.sqrt(5)) / 2;</p> <p>// This reassignment will be forbidden by the compiler: GOLDEN_RATIO = "new value";
es6.blockScoping
Enables thelet
andconst
keywords as alternatives tovar
. The key difference is that variables defined usinglet
orconst
are visible only within the block where they are declared, rather than being visible anywhere in the enclosing function. For example:function example(condition) { let x = 0; if (condition) { let x = 1; console.log(x); } else { console.log(x); x = 2; } return x; }</p> <p>example(true); // logs 1, returns 0 example(false); // logs 0, returns 2
es6.properties.shorthand
Allows omitting the value of an object literal property when the desired value is held by a variable that has the same name as the property key. For example, instead of writing{ x: x, y: y, z: "asdf" }
you can just write{ x, y, z: "asdf" }
. Methods can also be written without the: function
property syntax:js var obj = { oldWay: function (a, b) { ... }, newWay(a, b) { ... } };
es6.properties.computed
Allows object literal properties with dynamically computed keys:var counter = 0; function getKeyName() { return "key" + counter++; }</p> <p>var obj = { [getKeyName()]: "zero", [getKeyName()]: "one", };</p> <p>obj.key0; // "zero" obj.key1; // "one"
es6.parameters
Default expressions for function parameters, evaluated whenever the parameter isundefined
,...rest
parameters for capturing remaining arguments without using thearguments
object:function add(a = 0, ...rest) { rest.forEach(n => a += n); return a; }</p> <p>add(); // 0 add(1, 2, 3); // 6
es6.spread
Allows an array of arguments to be interpolated into a list of arguments to a function call,new
expression, or array literal, without usingFunction.prototype.apply
:js add(1, ...[2, 3, 4], 5); // 15 new Node("name", ...children); [1, ...[2, 3, 4], 5]; // [1, 2, 3, 4, 5]
es6.forOf
Provides an easy way to iterate over the elements of a collection:js let sum = 0; for (var x of [1, 2, 3]) { sum += x; } x; // 6
es6.destructuring
Destructuring is the technique of using an array or object pattern on the left-hand side of an assignment or declaration, in place of the usual variable or parameter, so that certain sub-properties of the value on the right-hand side will be bound to identifiers that appear within the pattern. Perhaps the simplest example is swapping two variables without using a temporary variable:js [a, b] = [b, a];
Extracting a specific property from an object:js let { username: name } = user; // is equivalent to let name = user.username;
Instead of taking a single opaqueoptions
parameter, a function can use an object destructuring pattern to name the expected options:function run({ command, args, callback }) { ... }</p> <p>run({ command: "git", args: ["status", "."], callback(error, status) { ... }, unused: "whatever" });
es7.objectRestSpread
Supports catch-all...rest
properties in object literal declarations and assignments:js let { x, y, ...rest } = { x: 1, y: 2, a: 3, b: 4 }; x; // 1 y; // 2 rest; // { a: 3, b: 4 }
Also enables...spread
properties in object literal expressions:js let n = { x, y, ...rest }; n; // { x: 1, y: 2, a: 3, b: 4 }
es7.trailingFunctionCommas
Allows the final parameter of a function to be followed by a comma, provided that parameter is not a...rest
parameter.flow
Permits the use of Flow type annotations. These annotations are simply stripped from the code, so they have no effect on the code's behavior, but you can run theflow
tool over your code to check the types if desired.
Polyfills
The ECMAScript 2015 standard library has grown to include new APIs and
data structures, some of which can be implemented ("polyfilled") using
JavaScript that runs in all engines and browsers today. Here are three new
constructors that are guaranteed to be available when the ecmascript
package is installed:
Promise
APromise
allows its owner to wait for a value that might not be available yet. See this tutorial for more details about the API and motivation. The MeteorPromise
implementation is especially useful because it runs all callback functions in recycledFiber
s, so you can use any Meteor API, including those that yield (e.g.HTTP.get
,Meteor.call
, orMongoCollection
), and you never have to callMeteor.bindEnvironment
.Map
An associative key-value data structure where the keys can be any JavaScript value (not just strings). Lookup and insertion take constant time.Set
A collection of unique JavaScript values of any type. Lookup and insertion take constant time.Symbol
An implementation of the globalSymbol
s namespace that enables a number of other ES2015 features, such asfor
-of
loops andSymbol.iterator
methods:[1,2,3][Symbol.iterator]()
.Polyfills for the following
Object
-related methods:Object.assign
Object.is
Object.setPrototypeOf
Object.prototype.toString
(fixes@@toStringTag
support)
Complete reference here.
Polyfills for the following
String
-related methods:String.fromCodePoint
String.raw
String.prototype.includes
String.prototype.startsWith
String.prototype.endsWith
String.prototype.repeat
String.prototype.codePointAt
String.prototype.trim
Complete reference here.
Polyfills for the following
Array
-related methods:Array.from
Array.of
Array.prototype.copyWithin
Array.prototype.fill
Array.prototype.find
Array.prototype.findIndex
Complete reference here.
Polyfills for the following
Function
-related properties:Function.prototype.name
(fixes IE9+)Function.prototype[Symbol.hasInstance]
(fixes IE9+)
Complete reference here.
jquery
jQuery is a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, animating, and Ajax interactions for rapid web development.
The jquery
package adds the jQuery library to the client JavaScript
bundle. It has no effect on the server.
In addition to the jquery
package, Meteor provides several jQuery
plugins as separate packages. These include:
less
LESS extends CSS with dynamic behavior such as variables, mixins, operations and functions. It allows for more compact stylesheets and helps reduce code duplication in CSS files.
With the less
package installed, .less
files in your application are
automatically compiled to CSS and the results are included in the client CSS
bundle.
If you want to @import
a file, give it the extension .import.less
to prevent Meteor from processing it independently.
markdown
This package lets you use Markdown in your templates. It's easy: just
put your markdown inside {{#markdown}} ... {{/markdown}}
tags. You can still use all of the usual Meteor template features
inside a Markdown block, such as {{#each}}
, and you still get
reactivity.
Example:
{{#markdown}}I am using __markdown__.{{/markdown}}
outputs
<p>I am using <strong>markdown</strong>.</p>
modules
Though Meteor 1.2 introduced support for many new ECMAScript 2015 features, one of the most notable omissions was ES2015 import
and export
syntax. Meteor 1.3 fills that gap with a fully standards-compliant module system that works on both the client and the server, solves multiple long-standing problems for Meteor applications (such as controlling file load order), and yet maintains full backwards compatibility with existing Meteor code. This document explains the usage and key features of the new module system.
Enabling modules
We think you’re going to love the new module system, and that's why it will be installed by default for all new apps and packages. Nevertheless, the modules
package is totally optional, and it will be up to you to add it to existing apps and/or packages.
For apps, this is as easy as meteor add modules
, or (even better) meteor add ecmascript
, since the ecmascript
package implies the modules
package.
For packages, you can enable modules
by adding api.use("modules")
to the Package.onUse
or Package.onTest
sections of your package.js
file.
Now, you might be wondering what good the modules
package is without the ecmascript
package, since ecmascript
enables import
and export
syntax. By itself, the modules
package provides the CommonJS require
and exports
primitives that may be familiar if you’ve ever written Node code, and the ecmascript
package simply compiles import
and export
statements to CommonJS. The require
and export
primitives also allow Node modules to run within Meteor application code without modification. Furthermore, keeping modules
separate allows us to use require
and exports
in places where using ecmascript
is tricky, such as the implementation of the ecmascript
package itself.
While the modules
package is useful by itself, we very much encourage using the ecmascript
package (and thus import
and export
) instead of using require
and exports
directly. If you need convincing, here’s a presentation that explains the differences: http://benjamn.github.io/empirenode-2015
Basic syntax
Although there are a number of different variations of import
and export
syntax, this section describes the essential forms that everyone should know.
First, you can export
any named declaration on the same line where it was declared:
// exporter.js
export var a = ...;
export let b = ...;
export const c = ...;
export function d() {...}
export function* e() {...}
export class F {...}
These declarations make the variables a
, b
, c
(and so on) available not only within the scope of the exporter.js
module, but also to other modules that import
from exporter.js
.
If you prefer, you can export
variables by name, rather than prefixing their declarations with the export
keyword:
// exporter.js
function g() {...}
let h = g();
// at the end of the file
export {g, h};
All of these exports are named, which means other modules can import them using those names:
// importer.js
import {a, c, F, h} from "./exporter";
new F(a, c).method(h);
If you’d rather use different names, you’ll be glad to know export
and import
statements can rename their arguments:
// exporter.js
export {g as x};
g(); // same as calling y() in importer.js
// importer.js
import {x as y} from "./exporter";
y(); // same as calling g() in exporter.js
As with CommonJS module.exports
, it is possible to define a single default export:
// exporter.js
export default any.arbitrary(expression);
This default export may then be imported without curly braces, using any name the importing module chooses:
// importer.js
import Value from "./exporter";
// Value is identical to the exported expression
Unlike CommonJS module.exports
, the use of default exports does not prevent the simultaneous use of named exports. Here is how you can combine them:
// importer.js
import Value, {a, F} from "./exporter";
In fact, the default export is conceptually just another named export whose name happens to be "default":
// importer.js
import {default as Value, a, F} from "./exporter";
These examples should get you started with import
and export
syntax. For further reading, here is a very detailed explanation by Axel Rauschmayer of every variation of import
and export
syntax.
Modular application structure
Before the release of Meteor 1.3, the only way to share values between files in an application was to assign them to global variables or communicate through shared variables like Session
(variables which, while not technically global, sure do feel syntactically identical to global variables). With the introduction of modules, one module can refer precisely to the exports of any other specific module, so global variables are no longer necessary.
If you are familiar with modules in Node, you might expect modules not to be evaluated until the first time you import them. However, because earlier versions of Meteor evaluated all of your code when the application started, and we care about backwards compatibility, eager evaluation is still the default behavior.
If you would like a module to be evaluated lazily (in other words: on demand, the first time you import it, just like Node does it), then you should put that module in an imports/
directory (anywhere in your app, not just the root directory), and include that directory when you import the module: import {stuff} from "./imports/lazy"
. Note: files contained by node_modules/
directories will also be evaluated lazily (more on that below).
Lazy evaluation will very likely become the default behavior in a future version of Meteor, but if you want to embrace it as fully as possible in the meantime, we recommend putting all your modules inside either client/imports/
or server/imports/
directories, with just a single entry point for each architecture: client/main.js
and server/main.js
. The main.js
files will be evaluated eagerly, giving your application a chance to import modules from the imports/
directories.
Modular package structure
If you are a package author, in addition to putting api.use("modules")
or api.use("ecmascript")
in the Package.onUse
section of your package.js
file, you can also use a new API called api.mainModule
to specify the main entry point for your package:
Package.describe({
name: "my-modular-package"
});
Npm.depends({
moment: "2.10.6"
});
Package.onUse(function (api) {
api.use("modules");
api.mainModule("server.js", "server");
api.mainModule("client.js", "client");
api.export("Foo");
});
Now server.js
and client.js
can import other files from the package source directory, even if those files have not been added using the api.addFiles
function.
When you use api.mainModule
, the exports of the main module are exposed globally as Package["my-modular-package"]
, along with any symbols exported by api.export
, and thus become available to any code that imports the package. In other words, the main module gets to decide what value of Foo
will be exported by api.export
, as well as providing other properties that can be explicitly imported from the package:
// In an application that uses my-modular-package:
import {Foo as ExplicitFoo, bar} from "meteor/my-modular-package";
console.log(Foo); // Auto-imported because of api.export.
console.log(ExplicitFoo); // Explicitly imported, but identical to Foo.
console.log(bar); // Exported by server.js or client.js, but not auto-imported.
Note that the import
is from "meteor/my-modular-package"
, not from "my-modular-package"
. Meteor package identifier strings must include the prefix meteor/...
to disambiguate them from npm packages.
Finally, since this package is using the new modules
package, and the package Npm.depends
on the "moment" npm package, modules within the package can import moment from "moment"
on both the client and the server. This is great news, because previous versions of Meteor allowed npm imports only on the server, via Npm.require
.
Local node_modules
Before Meteor 1.3, the contents of node_modules
directories in Meteor application code were completely ignored. When you enable modules
, those useless node_modules
directories suddenly become infinitely more useful:
meteor create modular-app
cd modular-app
mkdir node_modules
npm install moment
echo 'import moment from "moment";' >> modular-app.js
echo 'console.log(moment().calendar());' >> modular-app.js
meteor
When you run this app, the moment
library will be imported on both the client and the server, and both consoles will log output similar to: Today at 7:51 PM
. Our hope is that the possibility of installing Node modules directly within an app will reduce the need for npm wrapper packages such as https://atmospherejs.com/momentjs/moment.
A version of the npm
command comes bundled with every Meteor installation, and (as of Meteor 1.3) it's quite easy to use: meteor npm ...
is synonymous with npm ...
, so meteor npm install moment
will work in the example above. (Likewise, if you don't have a version of node
installed, or you want to be sure you're using the exact same version of node
that Meteor uses, meteor node ...
is a convenient shortcut.) That said, you can use any version of npm
that you happen to have available. Meteor's module system only cares about the files installed by npm
, not the details of how npm
installs those files.
File load order
Before Meteor 1.3, the order in which application files were evaluated was dictated by a set of rules described in the Application Structure - Default file load order section of the Meteor Guide. These rules could become frustrating when one file depended on a variable defined by another file, particularly when the first file was evaluated after the second file.
Thanks to modules, any load-order dependency you might imagine can be resolved by adding an import
statement. So if a.js
loads before b.js
because of their file names, but a.js
needs something defined by b.js
, then a.js
can simply import
that value from b.js
:
// a.js
import {bThing} from "./b";
console.log(bThing, "in a.js");
// b.js
export var bThing = "a thing defined in b.js";
console.log(bThing, "in b.js");
Sometimes a module doesn’t actually need to import anything from another module, but you still want to be sure the other module gets evaluated first. In such situations, you can use an even simpler import
syntax:
// c.js
import "./a";
console.log("in c.js");
No matter which of these modules is imported first, the order of the console.log
calls will always be:
console.log(bThing, "in b.js");
console.log(bThing, "in a.js");
console.log("in c.js");
oauth-encryption
Encrypts sensitive login secrets stored in the database such as a login service's application secret key and users' access tokens.
Generating a Key
The encryption key is 16 bytes, encoded in base64.
To generate a key:
$ ~/.meteor/tools/latest/bin/node -e 'console.log(require("crypto").randomBytes(16).toString("base64"))'
Using oauth-encryption with accounts
On the server only, use the oauthSecretKey
option to Accounts.config
:
Accounts.config({oauthSecretKey: "onsqJ+1e4iGFlV0nhZYobg=="});
This call to Accounts.config
should be made at load time (place at
the top level of your source file), not called from inside of a
Meteor.startup
block.
To avoid storing the secret key in your application's source code, you
can use Meteor.settings
:
Accounts.config({oauthSecretKey: Meteor.settings.oauthSecretKey});
Migrating unencrypted user tokens
This example for Twitter shows how existing unencrypted user tokens
can be encrypted. The query finds user documents which have a Twitter
access token but not the algorithm
field which is created when the
token is encrypted. The relevant fields in the service data are then
encrypted.
Meteor.users.find({ $and: [
{ 'services.twitter.accessToken': {$exists: true} },
{ 'services.twitter.accessToken.algorithm': {$exists: false} }
] }).
forEach(function (userDoc) {
var set = {};
_.each(['accessToken', 'accessTokenSecret', 'refreshToken'], function (field) {
var plaintext = userDoc.services.twitter[field];
if (!_.isString(plaintext))
return;
set['services.twitter.' + field] = OAuthEncryption.seal(
userDoc.services.twitter[field],
userDoc._id
);
});
Meteor.users.update(userDoc._id, {$set: set});
});
Using oauth-encryption without accounts
If you're using the oauth packages directly instead of through the
Meteor accounts packages, you can load the OAuth encryption key
directly using OAuthEncryption.loadKey
:
OAuthEncryption.loadKey("onsqJ+1e4iGFlV0nhZYobg==");
If you call retrieveCredential
(such as
Twitter.retrieveCredential
) as part of your process, you'll find
when using oauth-encryption that the sensitive service data fields
will be encrypted.
You can decrypt them using OAuth.openSecrets
:
var credentials = Twitter.retrieveCredential(token);
var serviceData = OAuth.openSecrets(credentials.serviceData);
Using oauth-encryption on Windows
This package depends on npm-node-aes-gcm, which requires you to have OpenSSL installed on your system to run. To install OpenSSL on Windows, use one of the binaries on this page. Don't forget to install the Visual Studio 2008 redistributables if you don't have them yet.
random
The random
package provides several functions for generating random
numbers. It uses a cryptographically strong pseudorandom number generator when
possible, but falls back to a weaker random number generator when
cryptographically strong randomness is not available (on older browsers or on
servers that don't have enough entropy to seed the cryptographically strong
generator).
- Random.id([n])
Returns a unique identifier, such as
"Jjwjg6gouWLXhMGKW"
, that is likely to be unique in the whole world. The optional argumentn
specifies the length of the identifier in characters and defaults to 17.- Random.secret([n])
Returns a random string of printable characters with 6 bits of entropy per character. The optional argument
n
specifies the length of the secret string and defaults to 43 characters, or 256 bits of entropy. UseRandom.secret
for security-critical secrets that are intended for machine, rather than human, consumption.- Random.fraction()
Returns a number between 0 and 1, like
Math.random
.- Random.choice(arrayOrString)
Returns a random element of the given array or string.
- Random.hexString(n)
Returns a random string of
n
hexadecimal digits.
spacebars
Spacebars is a Meteor template language inspired by Handlebars. 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).
<template name="myPage">
<h1>{{pageTitle}}</h1>
{{> nav}}
{{#each posts}}
<div class="post">
<h3>{{title}}</h3>
<div class="post-content">
{{{content}}}
</div>
</div>
{{/each}}
</template>
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]
(numeric indices must be enclosed in brackets).
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 thefoo
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.
Note that the above two points interact in a way that can be surprising!
If foo
is a template helper function that returns another template, then
{{>foo bar}}
will first push bar
onto the data context stack then call
foo()
, due to the way this line is expanded as shown above. You will need to
use Template.parentData(1)
to access the original context. This differs
from regular helper calls like {{foo bar}}
, in which bar
is passed as a
parameter rather than pushed onto the data context stack.
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 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