mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
1664 lines
62 KiB
HTML
1664 lines
62 KiB
HTML
<template name="api">
|
|
{{#better_markdown}}
|
|
|
|
<h1 id="api">The Meteor API</h1>
|
|
|
|
Your Javascript code can run in two environments: the <i>client</i>
|
|
(browser), and the <i>server</i> (a Node.js container on a server). For
|
|
each function in this API reference, we'll indicate if the function is
|
|
available just on the client, just on the server, or *Anywhere*.
|
|
|
|
<h2 id="core"><span>Meteor Core</span></h2>
|
|
|
|
{{> api_box is_client}}
|
|
{{> api_box is_server}}
|
|
{{> api_box startup}}
|
|
|
|
On a server, the function will run as soon as the server process is
|
|
finished starting. On a client, the function will run as soon as the DOM
|
|
is ready and any `<body>` templates from your `.html` files have been
|
|
put on the screen.
|
|
|
|
// On server startup, if the database is empty, create some initial data.
|
|
if (Meteor.is_server) {
|
|
Meteor.startup(function () {
|
|
if (Rooms.find().count() === 0) {
|
|
Rooms.insert({name: "Initial room"});
|
|
}
|
|
});
|
|
}
|
|
|
|
<h2 id="publishandsubscribe"><span>Publish and subscribe</span></h2>
|
|
|
|
These functions control how Meteor servers publish sets of records and
|
|
how clients can subscribe to those sets.
|
|
|
|
{{> api_box publish}}
|
|
|
|
To publish records to clients, call `Meteor.publish` on the server with
|
|
two parameters: the name of the record set, and a *publish function*
|
|
that Meteor will call each time a client subscribes to the name.
|
|
|
|
Publish functions can return a
|
|
[`Collection.Cursor`](#meteor_collection_cursor), in which case Meteor
|
|
will publish that cursor's documents.
|
|
|
|
// server: publish the rooms collection, minus secret info.
|
|
Meteor.publish("rooms", function () {
|
|
return Rooms.find({}, {fields: {secret_info: false}});
|
|
});
|
|
|
|
Otherwise, the publish function can <i>set</i> and <i>unset</i>
|
|
individual record attributes on a client, use these methods provided by
|
|
`this` in your publish function.
|
|
|
|
<!-- discuss complete -->
|
|
|
|
In particular, if you use observe() to watch changes to the database, be
|
|
sure to call `this.flush` from inside your observe callbacks. Methods
|
|
that update the database are considered finished when the observe
|
|
callbacks return.
|
|
|
|
Example:
|
|
|
|
// server: publish the current size of a collection
|
|
Meteor.publish("counts-by-room", function (roomId) {
|
|
var self = this;
|
|
var uuid = Meteor.uuid();
|
|
var count = 0;
|
|
|
|
var handle = Messages.find({room_id: roomId}).observe({
|
|
added: function (doc, idx) {
|
|
count++;
|
|
self.set("counts", uuid, {roomId: roomId, count: count});
|
|
self.flush();
|
|
},
|
|
removed: function (doc, idx) {
|
|
count--;
|
|
self.set("counts", uuid, {roomId: roomId, count: count});
|
|
self.flush();
|
|
}
|
|
// don't care about moved or changed
|
|
});
|
|
|
|
// remove data and turn off observe when client unsubs
|
|
self.onStop(function () {
|
|
handle.stop();
|
|
self.unset("counts", uuid, ["roomId", "count"]);
|
|
self.flush();
|
|
});
|
|
});
|
|
|
|
// client: declare collection to hold count object
|
|
Counts = new Meteor.Collection("counts");
|
|
|
|
// client: autosubscribe to the count for the current room
|
|
Meteor.autosubscribe(function () {
|
|
Meteor.subscribe("counts-by-room", Session.get("roomId"));
|
|
});
|
|
|
|
// client: use the new collection
|
|
console.log("Current room has " + Counts.findOne().count + " messages.");
|
|
|
|
{{#warning}}
|
|
Meteor will emit a warning message if you call `Meteor.publish` in a
|
|
project that includes the `autopublish` package. Your publish function
|
|
will still work.
|
|
{{/warning}}
|
|
|
|
{{> api_box subscription_set}}
|
|
{{> api_box subscription_unset}}
|
|
{{> api_box subscription_complete}}
|
|
{{> api_box subscription_flush}}
|
|
|
|
{{> api_box subscription_onStop}}
|
|
|
|
If you call [`observe`](#observe) in your publish handler, this
|
|
is the place to stop the observes.
|
|
|
|
{{> api_box subscription_stop}}
|
|
|
|
{{> api_box subscribe}}
|
|
|
|
When you subscribe to a record set, it tells the server to send records
|
|
to the client. The client stores these records in local Minimongo
|
|
collections, with the same name as the `collection` argument to `set`.
|
|
Meteor will queue incoming attributes until you declare the
|
|
`Meteor.Collection` on the client with the matching collection name.
|
|
|
|
// okay to subscribe (and possibly receive data) before declaring
|
|
// the client collection that will hold it. assume "allplayers"
|
|
// publishes data from server's "players" collection.
|
|
Meteor.subscribe("allplayers");
|
|
...
|
|
// client queues incoming players records until ...
|
|
...
|
|
Players = new Meteor.Collection("players");
|
|
|
|
If more than one subscription sends conflicting values for an attribute
|
|
(same collection name, document ID, and attribute name), then the value
|
|
on the client will be that from the *first* subscription the client
|
|
activated. (Even if it is not the first to send the duplicated
|
|
attribute.)
|
|
|
|
If all of the attributes in a document are removed, Meteor
|
|
will remove the (now empty) document. If you want to publish empty
|
|
documents, just use a placeholder attribute.
|
|
|
|
// Clicks.insert({exists: true});
|
|
|
|
{{> api_box autosubscribe}}
|
|
|
|
`func` will be run immediately, and while it runs,
|
|
records will be kept of the subscriptions it makes
|
|
(via [`Meteor.subscribe`](#meteor_subscribe)) and the data it uses
|
|
(including calls to [`Session.get`](#session_get)
|
|
and [`collection.find`](#find)).
|
|
|
|
Whenever the used data changes, the subscriptions will be cancelled and
|
|
`func` will be re-run to make replacement subscriptions.
|
|
`Meteor.autosubscribe` will automatically stop the old subscription.
|
|
It's not necessary to call `stop` on subscriptions made from inside
|
|
`Meteor.autosubscribe`.
|
|
|
|
Example:
|
|
|
|
// Subscribe to the chat messages in the current room. Automatically
|
|
// update the subscription whenever the current room changes.
|
|
Meteor.autosubscribe(function () {
|
|
Meteor.subscribe("chat", {room: Session.get("current-room");});
|
|
});
|
|
|
|
<h2 id="methods_header"><span>Methods</span></h2>
|
|
|
|
Methods are remote functions that Meteor clients can invoke.
|
|
|
|
{{> api_box methods}}
|
|
|
|
Example:
|
|
|
|
Meteor.methods({
|
|
foo: function (arg1, arg2) {
|
|
// .. do stuff ..
|
|
if (you want to throw an error)
|
|
throw new Meteor.Error(404, "Can't find my pants");
|
|
return "some return value";
|
|
},
|
|
|
|
bar: function () {
|
|
// .. do other stuff ..
|
|
return "baz";
|
|
}
|
|
});
|
|
|
|
Calling `methods` on the server defines functions that can be called
|
|
remotely by clients. They should return a value or throw an exception.
|
|
Inside your method invocation, `this` is bound to a method invocation
|
|
object, which provides the following:
|
|
|
|
* `is_simulation`: a boolean value, true if this invocation is a stub.
|
|
* `unblock`: when called, allows the next method from this client to
|
|
begin running.
|
|
|
|
Calling `methods` on the client defines *stub* functions associated with
|
|
server methods of the same name. You don't have to define a stub for
|
|
your method if you don't want to. In that case, method calls are just
|
|
like remote procedure calls in other systems, and you'll have to wait
|
|
for the results from the server.
|
|
|
|
If you do define a stub, when a client invokes a server method it will
|
|
also run its stub in parallel. On the client, the return value of a
|
|
stub is ignored. Stubs are run for their side-effects: they are
|
|
intended to *simulate* the result of what the server's method will do,
|
|
but without waiting for the round trip delay. If a stub throws an
|
|
exception it will be logged to the console.
|
|
|
|
{{> api_box method_invocation_is_simulation}}
|
|
|
|
{{> api_box method_invocation_unblock}}
|
|
|
|
On the server, methods from a given client run one at a time. The N+1th
|
|
invocation from a client won't start until the Nth invocation
|
|
returns. However, you can change this by calling `this.unblock`. This
|
|
will allow the N+1th invocation to start running in a new fiber.
|
|
|
|
{{> api_box error}}
|
|
|
|
If you want to return an error from a method, throw an exception.
|
|
Methods can throw any kind of exception. But `Meteor.Error` is the only
|
|
kind of error that a server will send to the client. If a method
|
|
function throws a different exception, then it will be mapped to
|
|
`Meteor.Error(500, "Internal server error")` on the wire.
|
|
|
|
{{> api_box meteor_call}}
|
|
|
|
This is how to invoke a method. It will run the method on the server.
|
|
If a stub is available, it will also run the stub on the client.
|
|
|
|
If you include a callback function as the last argument (which can't be
|
|
an argument to the method, since functions aren't serializeable), the
|
|
method will run asynchronously: it will return nothing in particular and
|
|
will not throw an exception. When the method is complete (which may or
|
|
may not happen before `Meteor.call` returns), the callback will be
|
|
called with two arguments: `error` and `result`. If an error was thrown,
|
|
then `error` will be the exception object. Otherwise, `error` will be
|
|
undefined and the return value (possibly undefined) will be in `result`.
|
|
|
|
// async call
|
|
Meteor.call('foo', 1, 2, function (error, result) { ... } );
|
|
|
|
If you do not pass a callback on the server, the method invocation will
|
|
block until the method is complete. It will eventually return the
|
|
return value of the method, or it will throw an exception if the method
|
|
threw an exception. (Possibly mapped to 500 Server Error if the
|
|
exception happened remotely and it was not a `Meteor.Error` exception.)
|
|
|
|
// sync call
|
|
var result = Meteor.call('foo', 1, 2);
|
|
|
|
On the client, if you do not pass a callback and you are not inside a
|
|
stub, `call` will return `undefined`, and you will have no way to get
|
|
the return value of the method. That is because the client doesn't have
|
|
fibers, so there is not actually any way it can block on the remote
|
|
execution of a method.
|
|
|
|
Finally, if you are inside a stub on the client and call another
|
|
method, the other method is not executed (no RPC is generated, nothing
|
|
"real" happens.) If that other method has a stub, that stub stands in
|
|
for the method and is executed. The method call's return value is the
|
|
return value of the stub function. The client has no problem executing
|
|
a stub synchronously, and that is why it's okay for the client to use
|
|
the synchronous `Meteor.call` form from inside a method body, as
|
|
described earlier.
|
|
|
|
You use this functionality all the time, because the database mutators
|
|
(`insert`, `update`, `remove`) are essentially methods. When you call
|
|
them on the client (whether from inside a method or at top level), you're
|
|
invoking their stub versions that update the local cache, instead of
|
|
their "real" versions that update the database (using credentials known
|
|
only to the server.)
|
|
|
|
{{> api_box meteor_apply}}
|
|
|
|
`Meteor.apply` is just like `Meteor.call`, but it allows the
|
|
arguments to be passed as an array.
|
|
|
|
<h2 id="connections"><span>Server connections</span></h2>
|
|
|
|
These functions manage and inspect the network connection between the
|
|
Meteor client and server.
|
|
|
|
{{> api_box status}}
|
|
|
|
This method returns the status of the connection between the client and
|
|
the server. The return value is an object with the following fields:
|
|
|
|
<dl class="objdesc">
|
|
<dt><span class="name">connected</span>
|
|
<span class="type">Boolean</span></dt>
|
|
<dd>True if currently connected to the server. If false, changes and
|
|
method invocations will be queued up until the connection is
|
|
reestablished.</dd>
|
|
|
|
<dt><span class="name">status</span>
|
|
<span class="type">String</span></dt>
|
|
<dd>Describes the current reconnection status. The possible
|
|
values are <code>connected</code> (the connection is up and
|
|
running), <code>connecting</code> (disconnected and trying to open a
|
|
new connection), and <code>waiting</code> (failed to connect and
|
|
waiting to try to reconnect).</dd>
|
|
|
|
<dt><span class="name">retry_count</span>
|
|
<span class="type">Number</span></dt>
|
|
<dd>The number of times the client has tried to reconnect since the
|
|
connection was lost. 0 when connected.</dd>
|
|
|
|
<dt><span class="name">retry_time</span>
|
|
<span class="type">Number or undefined</span></dt>
|
|
<dd>The estimated time of the next reconnection attempt. To turn this
|
|
into an interval until the next reconnection, use
|
|
<code>retry_time - (new Date()).getTime()</code>. This key will
|
|
be set only when <code>status</code> is <code>waiting</code>.
|
|
</dd>
|
|
</dl>
|
|
|
|
Instead of using callbacks to notify you on changes, this is
|
|
a <a href="#reactivity">reactive</a> data source. You can use it in a
|
|
<a href="#templates">template</a> or <a href="#meteor_deps">invalidation
|
|
context</a> to get realtime updates.
|
|
|
|
{{> api_box reconnect}}
|
|
|
|
{{> api_box connect}}
|
|
|
|
To call methods on another Meteor application or subscribe to its data
|
|
sets, call `Meteor.connect` with the URL of the application.
|
|
`Meteor.connect` returns an object which provides:
|
|
|
|
* `subscribe`
|
|
* `methods` (to define stubs)
|
|
* `call`
|
|
* `apply`
|
|
* `status`
|
|
* `reconnect`
|
|
|
|
When you call `Meteor.subscribe`, `Meteor.status`, `Meteor.call`, and
|
|
`Meteor.apply`, you are using a connection back to that default
|
|
server.
|
|
|
|
{{#warning}}
|
|
In this release, `Meteor.connect` can only be called on the client.
|
|
Servers can not yet connect to other servers.
|
|
{{/warning}}
|
|
|
|
<h2 id="collections"><span>Collections</span></h2>
|
|
|
|
Meteor stores data in *collections*. To get started, declare a
|
|
collection with `new Meteor.Collection`.
|
|
|
|
{{> api_box meteor_collection}}
|
|
|
|
Calling this function is analogous to declaring a model in an
|
|
traditional ORM (Object-Relation Mapper)-centric framework. It sets up a
|
|
*collection* (a storage space for records, or "documents") that can be
|
|
used to store a particular type of information, like users, posts,
|
|
scores, todo items, or whatever matters to your application. Each
|
|
document is a JSON object. It includes an `_id` property whose value is
|
|
unique in the collection, which Meteor will set when you first create
|
|
the document.
|
|
|
|
// common code on client and server declares livedata-managed mongo
|
|
// collection.
|
|
Chatrooms = new Meteor.Collection("chatrooms");
|
|
Messages = new Meteor.Collection("messages");
|
|
|
|
The function returns an object with methods to [`insert`](#insert)
|
|
documents in the collection, [`update`](#update) their properties, and
|
|
[`remove`](#remove) them, and to [`find`](#find) the documents in the
|
|
collection that match arbitrary criteria. The way these methods work is
|
|
compatible with the popular Mongo database API. The same database API
|
|
works on both the client and the server (see below).
|
|
|
|
// return array of my messages
|
|
var my_messages = Messages.find({user_id:Session.get('my_user_id')}).fetch();
|
|
|
|
// create a new message
|
|
Messages.insert({text: "Hello, world!"});
|
|
|
|
// mark my first message as "important"
|
|
Messages.update(my_messages[0].id, {$set: {important: true}});
|
|
|
|
If you pass a `name` when you create the collection, then you are
|
|
declaring a persistent collection — one that is stored on the
|
|
server and seen by all users. Client code and server code can both
|
|
access the same collection using the same API.
|
|
|
|
Specifically, when you pass a `name`, here's what happens:
|
|
|
|
* On the server, a collection with that name is created on a backend
|
|
Mongo server. When you call methods on that collection on the server,
|
|
they translate directly into normal Mongo operations.
|
|
|
|
* On the client, a Minimongo instance is
|
|
created. Minimongo is essentially an in-memory, non-persistent
|
|
implementation of Mongo in pure JavaScript. It serves as a local cache
|
|
that stores just the subset of the database that this client is working
|
|
with. Queries on the client ([`find`](#find)) are served directly out of
|
|
this cache, without talking to the server.
|
|
|
|
* When you write to the database on the client ([`insert`](#insert),
|
|
[`update`](#update), [`remove`](#remove)), the command is executed
|
|
immediately on the client, and, simultaneously, it's shipped up to the
|
|
server and executed there too. The `livedata` package is
|
|
responsible for this.
|
|
|
|
If you pass `null` as the `name`, then you're creating a local
|
|
collection. It's not synchronized anywhere; it's just a local scratchpad
|
|
that supports Mongo-style [`find`](#find), [`insert`](#insert),
|
|
[`update`](#update), and [`remove`](#remove) operations. (On both the
|
|
client and the server, this scratchpad is implemented using Minimongo.)
|
|
|
|
By default, Meteor automatically publishes every document in your
|
|
collection to each connected client. To turn this behavior off, remove
|
|
the package:
|
|
|
|
$ meteor remove autopublish
|
|
|
|
{{#warning}}
|
|
Currently the client is given full write access to the collection. They
|
|
can execute arbitrary Mongo update commands. Once we build
|
|
authentication, you will be able to limit the client's direct access to
|
|
insert, update, and remove. We are also considering validators and
|
|
other ORM-like functionality.
|
|
{{/warning}}
|
|
|
|
// Create a collection called Posts and put a document in it. The
|
|
// document will be immediately visible in the local copy of the
|
|
// collection. It will be written to the server-side database
|
|
// a fraction of a second later, and a fraction of a second
|
|
// after that, it will be synchronized down to any other clients
|
|
// that are subscribed to a query that includes it (see
|
|
// Meteor.subscribe and autopublish)
|
|
Posts = new Meteor.Collection("posts");
|
|
Posts.insert({title: "Hello world", body: "First post"});
|
|
|
|
// Changes are visible immediately -- no waiting for a round trip to
|
|
// the server.
|
|
assert(Posts.find().count() === 1);
|
|
|
|
// Create a temporary, local collection. It works just any other
|
|
// collection, but it doesn't send changes to the server, and it
|
|
// can't receive any data from subscriptions.
|
|
Scratchpad = new Meteor.Collection;
|
|
for (var i = 0; i < 10; i++)
|
|
Scratchpad.insert({number: i * 2});
|
|
assert(Scratchpad.find({number: {$lt: 9}}).count() === 5);
|
|
|
|
{{#warning}}
|
|
In this release, Minimongo has some limitations:
|
|
|
|
* `$elemMatch` is not supported in selectors.
|
|
* `$pull` in modifiers can only accept certain kinds
|
|
of selectors.
|
|
* In selectors, dot notation and ordinal indexing may not work correctly.
|
|
* `$` to denote the matched array position is not
|
|
supported in modifier.
|
|
* Sort does not support subkeys (you can sort on `a`,
|
|
but not `a.b`.)
|
|
* `findAndModify`, upsert, aggregate functions, and
|
|
map/reduce aren't supported.
|
|
* The supported types are String, Number, Boolean, Array,
|
|
and Object.
|
|
|
|
All of these will be addressed in a future release. For full
|
|
Minimongo release notes, see packages/minimongo/NOTES
|
|
in the repository.
|
|
{{/warning}}
|
|
|
|
{{#warning}}
|
|
Minimongo currently doesn't have indexes. This will come soon. It's
|
|
usually not an issue, since there usually isn't that much data in
|
|
the client — it is not that common for developers to implement
|
|
indexes in their client-side models anyway.
|
|
{{/warning}}
|
|
|
|
{{> api_box find}}
|
|
|
|
`find` returns a cursor. It does not immediately access the database or
|
|
return documents. Cursors provide `fetch` to return all matching
|
|
documents, `map` and `forEach` to iterate over all matching
|
|
documents, and `observe` to register callbacks when the set of
|
|
matching documents changes.
|
|
|
|
{{#warning}}
|
|
Collection cursors are not query snapshots. If the database changes
|
|
between calling `Collection.find` and fetching the
|
|
results of the cursor, or while fetching results from the cursor,
|
|
those changes may or may not appear in the result set.
|
|
{{/warning}}
|
|
|
|
Cursors are a reactive data source. The first time you retrieve a
|
|
cursor's documents with `fetch`, `map`, or `forEach` inside a
|
|
reactive context (eg, [`Meteor.ui.render`](#meteor_ui_render),
|
|
[`Meteor.autosubscribe`](#meteor_autosubscribe), Meteor will register a
|
|
dependency on the underlying data. Any change to the collection that
|
|
changes the documents in a cursor will trigger a recomputation. To
|
|
disable this behavior, pass `{reactive: false}` as an option to
|
|
`find`.
|
|
|
|
{{> api_box findone}}
|
|
|
|
Equivalent to `find(selector, options).fetch()[0]`.
|
|
|
|
{{> api_box insert}}
|
|
|
|
Add a document to the collection. A document is just an object, and
|
|
its fields can contain any combination of JSON-compatible datatypes
|
|
(arrays, objects, numbers, strings, null, true, and false).
|
|
|
|
`insert` will generate a unique ID for the object you pass, insert it
|
|
in the database, and return the ID.
|
|
|
|
On the server, if you don't provide a callback, then `insert` blocks
|
|
until the database acknowledges the write, or throws an exception if
|
|
something went wrong. If you do provide a callback, `insert` still
|
|
returns the ID immediately. Once the insert completes (or fails), the
|
|
callback is called with error and result arguments. In an error case,
|
|
`result` is undefined. If the insert is successful, `error` is
|
|
undefined and `result` is the new document ID.
|
|
|
|
On the client, `insert` never blocks. If you do not provide a callback
|
|
and the insert fails on the server, then Meteor will log a warning to
|
|
the console. If you provide a callback, Meteor will call that function
|
|
with `error` and `result` arguments. In an error case, `result` is
|
|
undefined. If the insert is successful, `error` is undefined and
|
|
`result` is the new document ID.
|
|
|
|
Example:
|
|
|
|
var groceries_id = Lists.insert({name: "Groceries"});
|
|
Items.insert({list: groceries_id, name: "Watercress"});
|
|
Items.insert({list: groceries_id, name: "Persimmons"});
|
|
|
|
{{> api_box update}}
|
|
|
|
Modify documents that match `selector` as
|
|
given by `modifier` (see <a href="#modifiers">modifier
|
|
documentation</a>). By default, modify only one matching document.
|
|
If `multi` is true, modify all matching documents.
|
|
|
|
Instead of a selector, you can pass a string, which will be
|
|
interpreted as an `_id`.
|
|
|
|
On the server, if you don't provide a callback, then `update` blocks
|
|
until the database acknowledges the write, or throws an exception if
|
|
something went wrong. If you do provide a callback, `update` returns
|
|
immediately. Once the update completes, the callback is called with a
|
|
single error argument in the case of failure, or no arguments if the
|
|
update was successful.
|
|
|
|
On the client, `update` never blocks. If you do not provide a callback
|
|
and the update fails on the server, then Meteor will log a warning to
|
|
the console. If you provide a callback, Meteor will call that function
|
|
with an error argument if there was an error, or no arguments if the
|
|
update was successful.
|
|
|
|
Example:
|
|
|
|
// Give the "Superlative" badge to each user with a score greater than
|
|
// 10. If they are logged in and their badge list is visible on the
|
|
// screen, it will update automatically as they watch.
|
|
Users.update({score: {$gt: 10}},
|
|
{$addToSet: {badges: "Superlative"}},
|
|
{multi: true});
|
|
|
|
{{#warning}}
|
|
The Mongo `upsert` feature is not implemented.
|
|
{{/warning}}
|
|
|
|
{{> api_box remove}}
|
|
|
|
Find all of the documents that match `selector` and delete them from the
|
|
collection. Or instead of a selector, you may pass a string, to delete
|
|
the document with that `_id`. As a safety measure, do nothing if the
|
|
selector is undefined. If the selector is `{}`, remove all the
|
|
documents from the collection.)
|
|
|
|
On the server, if you don't provide a callback, then `remove` blocks
|
|
until the database acknowledges the write, or throws an exception if
|
|
something went wrong. If you do provide a callback, `remove` returns
|
|
immediately. Once the remove completes, the callback is called with a
|
|
single error argument in the case of failure, or no arguments if the
|
|
update was successful.
|
|
|
|
On the client, `remove` never blocks. If you do not provide a callback
|
|
and the remove fails on the server, then Meteor will log a warning to
|
|
the console. If you provide a callback, Meteor will call that function
|
|
with an error argument if there was an error, or no arguments if the
|
|
update was successful.
|
|
|
|
Example:
|
|
|
|
// Delete all users with a karma of less than -2.
|
|
Users.remove({karma: {$lt: -2}});
|
|
|
|
// Delete all the log entries
|
|
Logs.remove({});
|
|
|
|
// Show a list of posts that have been flagged, updating in realtime.
|
|
// Put a link next to each post that deletes the post if clicked.
|
|
var frag = Meteor.ui.render(function() {
|
|
return Meteor.ui.listChunk(
|
|
Posts.find({flagged: true}),
|
|
function (post) {
|
|
// In real code it'd be necessary to sanitize post.name
|
|
return "<div>" + post.name +
|
|
" <span class='delete'>Delete</span></div>";
|
|
},
|
|
{ events: {
|
|
'click .delete': function () {
|
|
Posts.remove(this._id);
|
|
}
|
|
}});
|
|
});
|
|
document.body.appendChild(frag);
|
|
|
|
<h2 id="meteor_collection_cursor"><span>Cursors</span></h2>
|
|
|
|
To create a cursor, use [`find`](#find). To access the documents in a
|
|
cursor, use [`forEach`](#foreach), [`map`](#map), or [`fetch`](#fetch).
|
|
|
|
{{> api_box cursor_foreach}}
|
|
|
|
When called in a reactive context, `forEach` registers dependencies on
|
|
the matching documents.
|
|
|
|
Examples:
|
|
|
|
// Print the titles of the five top-scoring posts
|
|
var top_posts = Posts.find({}, {sort: {score: -1}, limit: 5});
|
|
var count = 0;
|
|
top_posts.forEach(function (post) {
|
|
console.log("Title of post " + count + ": " + post.title);
|
|
count += 1;
|
|
});
|
|
|
|
{{> api_box cursor_map}}
|
|
|
|
When called in a reactive context, `map` registers dependencies on
|
|
the matching documents.
|
|
|
|
{{> api_box cursor_fetch}}
|
|
|
|
When called in a reactive context, `fetch` registers dependencies on
|
|
the matching documents.
|
|
|
|
{{> api_box cursor_count}}
|
|
|
|
// Display a count of posts matching certain criteria. Automatically
|
|
// keep it updated as the database changes.
|
|
var frag = Meteor.ui.render(function () {
|
|
var high_scoring = Posts.find({score: {$gt: 10}});
|
|
return "<p>There are " + high_scoring.count() + " posts with " +
|
|
"scores greater than 10</p>";
|
|
});
|
|
document.body.appendChild(frag);
|
|
|
|
Unlike the other functions, `count` registers a dependency only on the
|
|
number of matching documents. (Updates that just change or reorder the
|
|
documents in the result set will not trigger a recomputation.)
|
|
|
|
{{> api_box cursor_rewind}}
|
|
|
|
The `forEach`, `map`, or `fetch` methods can only be called once on a
|
|
cursor. To access the data in a cursor more than once, use `rewind` to
|
|
reset the cursor.
|
|
|
|
{{> api_box cursor_observe}}
|
|
|
|
Establishes a *live query* that notifies callbacks on any change to the
|
|
query result.
|
|
|
|
`callbacks` may have the following functions as properties:
|
|
|
|
<dl class="callbacks">
|
|
{{#dtdd "added(document, before_index)"}}
|
|
A new document entered the result set. It was inserted
|
|
immediately before the document currently at the
|
|
position `before_index`. Or if it was inserted at the end
|
|
of the list, `before_index` will be equal to the (prior)
|
|
length of the list.
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "changed(new_document, at_index, old_document)"}}
|
|
The contents of the document at position `at_index`
|
|
changed to `new_document`, was previously `old_document`.
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "moved(document, old_index, new_index)"}}
|
|
A document changed its position in the result set,
|
|
from `old_index` to `new_index`. For your
|
|
convenience, its current contents is `document`. (This will
|
|
only fire immediately after `changed`.
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "removed(old_document, at_index)"}}
|
|
The document at position `at_index`, which was previously
|
|
`old_document`, is no longer in the result set.
|
|
{{/dtdd}}
|
|
</dl>
|
|
|
|
`added` will immediately be called as necessary to
|
|
deliver the initial results of the query, if any.
|
|
|
|
`observe` returns a live query handle, which is an object with a
|
|
`stop` method. Call this function with no arguments to stop calling
|
|
the callback functions and tear down the query. **The query will run
|
|
forever until you call this.**
|
|
|
|
Example:
|
|
|
|
// Keep track of how many administrators are online.
|
|
var count = 0;
|
|
var query = Users.find({admin: true, online_now: true});
|
|
var handle = query.observe({
|
|
added: function (user) {
|
|
count++;
|
|
console.log(user.name + " brings the total to " + count + " admins.");
|
|
},
|
|
removed: function () {
|
|
count--;
|
|
console.log("Lost one. We're now down to " + count + " admins.");
|
|
}
|
|
});
|
|
|
|
// After five seconds, stop keeping the count.
|
|
setTimeout(function () {handle.stop();}, 5000);
|
|
|
|
{{#api_box_inline selectors}}
|
|
|
|
In its simplest form, a selector is just a set of keys that must
|
|
match in a document:
|
|
|
|
// Matches all documents where deleted is false
|
|
{deleted: false}
|
|
|
|
// Matches all documents where the name and cognomen are as given
|
|
{name: "Rhialto", cognomen: "the Marvelous"}
|
|
|
|
// Matches every document
|
|
{}
|
|
|
|
But they can also contain more complicated tests:
|
|
|
|
// Matches documents where age is greater than 18
|
|
{age: {$gt: 18}}
|
|
|
|
// Also matches documents where tags is an array containing "popular"
|
|
{tags: "popular"}
|
|
|
|
// Matches documents where fruit is one of three possibilities
|
|
{fruit: {$in: ["peach", "plum", "pear"]}}
|
|
|
|
See the <a href="http://www.mongodb.org/display/DOCS/Advanced+Queries" target="_blank">complete documentation.</a>
|
|
|
|
{{/api_box_inline}}
|
|
|
|
{{#api_box_inline modifiers}}
|
|
|
|
A modifier is an object that describes how to update a document in
|
|
place by changing some of its fields. Some examples:
|
|
|
|
// Set the 'admin' property on the document to true
|
|
{$set: {admin: true}}
|
|
|
|
// Add 2 to the 'votes' property, and add "Traz" to the end of the
|
|
// 'supporters' array
|
|
{$inc: {votes: 2}, $push: {supporters: "Traz"}}
|
|
|
|
But if a modifier doesn't contain any $-operators, then it is
|
|
instead interpreted as a literal document, and completely replaces
|
|
whatever was previously in the database.
|
|
|
|
// Find the document with id "123", and completely replace it.
|
|
Users.update({_id: "123"}, {name: "Alice", friends: ["Bob"]});
|
|
|
|
See the <a href="http://www.mongodb.org/display/DOCS/Updating#Updating-ModifierOperations" target="_blank">full list of modifiers.</a>
|
|
|
|
{{/api_box_inline}}
|
|
|
|
{{#api_box_inline sortspecifiers}}
|
|
|
|
Sorts may be specified using your choice of several syntaxes:
|
|
|
|
// All of these do the same thing (sort in ascending order by
|
|
// key "a", breaking ties in descending order of key "b")
|
|
|
|
[["a", "asc"], ["b", "desc"]]
|
|
["a", ["b", "desc"]]
|
|
{a: 1, b: -1}
|
|
|
|
The last form will only work if your JavaScript implementation
|
|
preserves the order of keys in objects. Most do, most of the time, but
|
|
it's up to you to be sure.
|
|
|
|
{{/api_box_inline}}
|
|
|
|
{{#api_box_inline fieldspecifiers}}
|
|
|
|
On the server, queries can specify a particular set of fields to include
|
|
or exclude from the result object. Minimongo ignores the field
|
|
specifier.
|
|
|
|
To exclude certain fields from the result objects, the field specifier
|
|
is a dictionary whose keys are field names and whose values are `0`.
|
|
|
|
// Users.find({}, {fields: {password: 0, hash: 0}})
|
|
|
|
To return an object that only includes the specified field, use `1` as
|
|
the value. The `_id` field is still included in the result.
|
|
|
|
// Users.find({}, {fields: {firstname: 1, lastname: 1}})
|
|
|
|
It is not possible to mix inclusion and exclusion styles.
|
|
|
|
{{/api_box_inline}}
|
|
|
|
<h2 id="session"><span>Session</span></h2>
|
|
|
|
`Session` provides a global object on the client that you can use to
|
|
store an arbitrary set of key-value pairs. Use it to store things like
|
|
the currently selected item in a list.
|
|
|
|
What's special about `Session` is that it's reactive. If
|
|
you call [`Session.get`](#session_get)`("current_list")`
|
|
from inside a template, the template will automatically be rerendered
|
|
whenever [`Session.set`](#session_set) is called.
|
|
|
|
{{> api_box set}}
|
|
|
|
Example:
|
|
|
|
Meteor.autosubcribe(function () {
|
|
Meteor.subscribe("chat-history", {room: Session.get("currentRoomId")});
|
|
});
|
|
|
|
// Causes the function passed to Meteor.autosubscribe to be re-run, so
|
|
// that the chat-history subscription is moved to the room "home".
|
|
Session.set("currentRoomId", "home");
|
|
|
|
See [`Meteor.deps`](#meteor_deps) for another example.
|
|
|
|
{{> api_box get}}
|
|
|
|
Example:
|
|
|
|
Session.set("enemy", "Eastasia");
|
|
var frag = Meteor.ui.render(function () {
|
|
return "<p>We've always been at war with " +
|
|
Session.get("enemy") + "</p>";
|
|
});
|
|
|
|
// Page will say "We've always been at war with Eastasia"
|
|
document.body.append(frag);
|
|
|
|
// Page will change to say "We've always been at war with Eurasia"
|
|
Session.set("enemy", "Eurasia");
|
|
|
|
{{> api_box equals}}
|
|
|
|
These two expressions do the same thing:
|
|
|
|
(1) Session.get("key") === value
|
|
(2) Session.equals("key", value)
|
|
|
|
... but the second one is always better. It triggers fewer invalidations
|
|
(template redraws), making your program more efficient.
|
|
|
|
Example:
|
|
|
|
<template name="posts_view">
|
|
{{dstache}}! Show a dynamically updating list of items. Let the user click on an
|
|
item to select it. The selected item is given a CSS class so it
|
|
can be rendered differently. }}
|
|
|
|
{{dstache}}#each posts}}
|
|
{{dstache}}> post_item }}
|
|
{{dstache}}/each}}
|
|
</{{! }}template>
|
|
|
|
<template name="post_item">
|
|
<div class="{{dstache}}post_class}}">{{dstache}}title}}</div>
|
|
</{{! }}template>
|
|
|
|
///// in JS file
|
|
Template.posts_view.posts = function() {
|
|
return Posts.find();
|
|
};
|
|
|
|
Template.post_item.post_class = function() {
|
|
return Session.equals("selected_post", this._id) ?
|
|
"selected" : "";
|
|
};
|
|
|
|
Template.post_item.events = {
|
|
'click': function() {
|
|
Session.set("selected_post", this._id);
|
|
}
|
|
};
|
|
|
|
// Using Session.equals here means that when the user clicks
|
|
// on an item and changes the selection, only the newly selected
|
|
// and the newly unselected items are re-rendered.
|
|
//
|
|
// If Session.get had been used instead of Session.equals, then
|
|
// when the selection changed, all the items would be re-rendered.
|
|
|
|
<h2 id="meteor_ui"><span>Meteor.ui</span></h2>
|
|
|
|
`Meteor.ui` provides building blocks for creating reactive UIs out of strings of
|
|
HTML, making it easy to create DOM elements that update
|
|
automatically as data changes in
|
|
[`Session`](#session) variables or in a
|
|
[`Meteor.Collection`](#meteor_collection). Meteor's built-in templates already use these functions, but if you prefer a different way of generating HTML,
|
|
are integrating a new template language with Meteor, or need to compose a reactive
|
|
snippet of HTML on the fly, then this package has what you need.
|
|
|
|
This package is implemented on top of [`Meteor.deps`](#meteor_deps), which provides the
|
|
data dependency tracking and invalidation system, while `Meteor.ui` contributes
|
|
the ability to turn HTML into DOM elements, keep track of regions of the DOM that
|
|
need updating, and patch old DOM content with new, recalculated content.
|
|
|
|
{{> api_box render}}
|
|
|
|
`Meteor.ui.render` creates a `DocumentFragment` (a sequence of DOM
|
|
nodes) that automatically updates in realtime. You pass in
|
|
`html_func`, a function that returns an HTML
|
|
string. `Meteor.ui.render` calls your function and turns the output
|
|
into DOM nodes. Meanwhile, it tracks the data that was used when
|
|
`html_func` ran, and automatically wires up callbacks so that whenever
|
|
any of the data changes, `html_func` is re-run and the DOM nodes
|
|
are updated in place.
|
|
|
|
Insert the returned `DocumentFragment` directly into the DOM wherever
|
|
you would like it to appear. The inserted nodes will continue to
|
|
update until they are taken off the screen. Then they will be
|
|
automatically cleaned up. For the details, see
|
|
[`Meteor.flush`](#meteor_flush).
|
|
|
|
You can also hook up events to the rendered DOM nodes using the
|
|
`events` option. If you provide `event_data`, it will be passed to
|
|
event handlers in `this`. (See [Event Maps](#eventmaps).)
|
|
|
|
When render replaces DOM elements because data changed, it can leave
|
|
input elements undisturbed so that focus is preserved, text entered
|
|
into fields isn't lost, and so forth. To activate this feature, give
|
|
each such element a unique `id`, or give it a unique `name` attribute
|
|
inside the nearest enclosing element with an `id`.
|
|
|
|
If you want a region of your HTML to be able to update independently
|
|
of the other HTML around it, wrap it in [`Meteor.ui.chunk`](#meteor_ui_chunk).
|
|
|
|
`Meteor.ui.render` tracks the data dependencies of `html_func` by
|
|
running it in a reactive context, so it can respond to changes in any
|
|
reactive data sources used by that function. For more information, or
|
|
to learn how to make your own reactive data sources, see
|
|
[Reactivity](#reactivity).
|
|
|
|
{{!
|
|
Meteor.ui.render runs html_func in a reactive context, then returns a
|
|
DocumentFragment that can be inserted anywhere in a Document and that
|
|
will automatically update itself in place whenever the context is
|
|
invalidated. The updating will stop if the nodes in the fragment are
|
|
ever not on the screen (that is, children of `window.document`) when
|
|
Meteor.flush runs.
|
|
|
|
During an update, if a node has a unique id, or if it has a name that
|
|
is unique among the descendants of the nearest enclosing parent that
|
|
has an id, then it will be "patched" (updated in place, rather than
|
|
replaced), meaning that focus will be preserved, the text in <input>
|
|
elements will be not be lost, etc.
|
|
|
|
|
|
By default, Meteor.ui.render puts the entire output of `html_func` in
|
|
a single invalidation context. For finer control of rerendering, you
|
|
can use Meteor.ui.chunk to create a nested tree of invalidation
|
|
contexts.
|
|
[events]
|
|
[more?]
|
|
}}
|
|
|
|
|
|
Example:
|
|
|
|
// Show the number of users online.
|
|
var frag = Meteor.ui.render(function () {
|
|
return "<p>There are " + Users.find({online: true}).count() +
|
|
" users online.</p>";
|
|
});
|
|
document.body.appendChild(frag);
|
|
|
|
// Find all users that have been idle for a while, and mark them as
|
|
// offline. The count on the screen will automatically update.
|
|
Users.update({idleTime: {$gt: 30}}, {online: false});
|
|
|
|
// Show a counter, and let the user click to increase or decrease it.
|
|
Session.set("counter", 0);
|
|
|
|
var frag = Meteor.ui.render(function () {
|
|
return '<div>Counter: ' + Session.get("counter") + ' ' +
|
|
'<span class="inc">Increase</span>' +
|
|
'<span class="dec">Decrease</span></div>';
|
|
}, { events:
|
|
{
|
|
'click .inc': function (event) {
|
|
Session.set("counter", Session.get("counter") + 1);
|
|
},
|
|
'click .dec': function (event) {
|
|
Session.set("counter", Session.get("counter") - 1);
|
|
}
|
|
}
|
|
});
|
|
document.body.appendChild(frag);
|
|
|
|
{{> api_box chunk}}
|
|
|
|
When generating HTML from a function passed to [`Meteor.ui.render`](#meteor_ui_render), you can use `Meteor.ui.chunk` to mark a substring of the HTML as separately reactive. If the data used to generate that substring changes, only the elements corresponding to that substring will be updated, not the elements before and after it.
|
|
|
|
Like `render`, `Meteor.ui.chunk` takes a function `html_func` that returns a HTML string. It calls that function, records the data that the function used (using a [reactive context](#meteor_ui_deps)), and arranges to rerun the function as necessary whenever the data changes. What's different from `render` is that it returns another HTML string, not a DocumentFragment. So, unlike `render`, `chunk` may be nested as deeply as you like, for example to render nested views or subtemplates.
|
|
|
|
`chunk` can also be used to attach events to part of an HTML string, in much the same way that they could be attached to DOM elements. When the string is parsed into DOM elements by `render`, the event handlers will automatically be hooked up. If `event_data` is provided, it sets the event data for _all_ events that occur that within the chunk, even when those events are handled by handlers declared in enclosing chunks.
|
|
|
|
{{#note}}
|
|
Note: In Internet Explorer 8 and
|
|
earlier, if you manually add elements to a chunk after it has been
|
|
rendered — for example, using jQuery or the DOM API — then handlers
|
|
in event maps may not fire on these elements. This is a limitation of the implementation.
|
|
{{/note}}
|
|
|
|
`chunk` works by creating a unique ID for the chunk, wrapping the HTML string in a comment that calls out that ID, and adding an entry to the chunk table for the current invocation of `render`. As `render` turns the HTML string into DOM nodes, it pulls out the comments and wires up the appropriate callbacks and pointers. On the other hand, if there is no current invocation of `render`, `chunk` just passes the string through unchanged. (In this case, if an event map is provided, it is ignored.)
|
|
|
|
The contents of a chunk must be balanced HTML tags; the string returned by
|
|
`html_func` cannot start or end inside a tag or tag attribute.
|
|
|
|
Example:
|
|
|
|
Meteor.startup(function() {
|
|
|
|
Session.set("greeting", "Hello");
|
|
Session.set("target", "World");
|
|
|
|
// Render two chunks that will be tracked and updated independently.
|
|
document.body.appendChild(
|
|
Meteor.ui.render(function() {
|
|
return "<div>" +
|
|
Meteor.ui.chunk(function() { return Session.get("greeting"); }) +
|
|
" " +
|
|
Meteor.ui.chunk(function() { return Session.get("target"); }) +
|
|
"</div>";
|
|
}));
|
|
|
|
// Updates "Hello" to "Goodbye" without touching "World"
|
|
Session.set("greeting", "Goodbye");
|
|
// Updates "World" to "Ralph" without touching "Goodbye"
|
|
Session.set("target", "Ralph");
|
|
|
|
});
|
|
|
|
// Every two seconds, alternates between Goodbye Ralph and Goodbye World.
|
|
// If you select the word Goodbye or part of it, the selection stays on
|
|
// update, because the text node is not being replaced.
|
|
Meteor.setInterval(function() {
|
|
if (Session.get("target") === "Ralph") {
|
|
Session.set("target", "World");
|
|
} else {
|
|
Session.set("target", "Ralph");
|
|
}
|
|
}, 2000);
|
|
|
|
|
|
{{> api_box listChunk}}
|
|
|
|
`listChunk` is like `chunk`, but instead of creating one chunk, it creates several, one for each record in the results of a database query.
|
|
|
|
It keeps the chunks updated as the results of the database query change. For example, if a new record is created in the database that matches the query, a new chunk is inserted. If the query is sorted, and a database record changes, and the change causes it to move in the sort order, then the chunk is moved appropriately.
|
|
|
|
If you provide `else_func`, then whenever the query returns no results, it will be called to render alternative content. You might use this to show a message like "No records match your query."
|
|
|
|
You can provide an `events` option to attach a set of event handlers to each chunk that `listChunk` creates. `event_data` is set to the corresponding database record in each chunk, meaning that when any event fires within a chunk, `this` in the event handler will contain the appropriate database record.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
// List the titles of all of the posts that have the tag
|
|
// "frontpage". Keep the list updated as new posts are made, as tags
|
|
// change, etc. Let the user click a post to select it.
|
|
Session.set("selected", null);
|
|
var frag = Meteor.ui.render(function() {
|
|
return Meteor.ui.listChunk(Posts.find({tags: "frontpage"}),
|
|
function(post) {
|
|
var style = Session.equals("selected", post._id) ? "selected" : "";
|
|
// A real app would need to quote/sanitize post.name
|
|
return '<div class="' + style + '">' + post.name + '</div>';
|
|
},
|
|
{ events:
|
|
{
|
|
'click': function (event) {
|
|
Session.set("selected", this._id);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
document.body.appendChild(frag);
|
|
|
|
{{> api_box flush }}
|
|
|
|
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.
|
|
|
|
`Meteor.flush` forces all of the pending reactive updates to complete
|
|
(for example, it ensures the DOM has been updated with your recent
|
|
database changes.) Call `flush` to apply those pending changes
|
|
immediately. The main use for this is to make sure the DOM has been
|
|
brought up to date with your latest changes, so you can manually
|
|
manipulate it with jQuery or the like.
|
|
|
|
When you call `flush`, any auto-updating DOM elements that are not on
|
|
the screen may be cleaned up (meaning that Meteor will stop tracking
|
|
and updating the elements, so that the browser's garbage collector can
|
|
delete them.) So, if you manually call `flush`, you need to make sure
|
|
that any auto-updating elements that you have created by calling
|
|
[`Meteor.ui.render`](#meteor_ui_render) have already been inserted in the main
|
|
DOM tree.
|
|
|
|
Technically speaking, `flush` calls the [invalidation
|
|
callbacks](#on_invalidate) on every [reactive context](#context) that
|
|
has been [invalidated](#invalidate), but hasn't yet has its callbacks
|
|
called. If the invalidation callbacks invalidate still more contexts,
|
|
flush keeps flushing until everything is totally settled. The DOM
|
|
elements are cleaned up because of logic in
|
|
[`Meteor.ui.render`](#meteor_ui_render) that works through invalidations.
|
|
|
|
{{#api_box_inline eventmaps}}
|
|
|
|
Several functions take 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:
|
|
|
|
<dl>
|
|
{{#dtdd "<em>eventtype</em>"}}
|
|
Matches a particular type of event, such as 'click'.
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "<em>eventtype selector</em>"}}
|
|
Matches a particular type of event, but only when it appears on
|
|
an element that matches a certain CSS selector.
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "<em>event1, event2</em>"}}
|
|
To handle more than one type of event with the same function, use a comma-separated list.
|
|
{{/dtdd}}
|
|
</dl>
|
|
|
|
The handler function gets one argument, an object with information
|
|
about the event. It will receive some additional context data in
|
|
`this`, depending on the context of the current element handling the event.
|
|
In a Handlebars template,
|
|
an element's context is the Handlebars data context where that element
|
|
occurs, which is set by block helpers such as `#with`
|
|
and `#each`. When using [`Meteor.ui.chunk`](#meteor_ui_chunk), the
|
|
data context is set using the `event_data` option.
|
|
|
|
Example:
|
|
|
|
{
|
|
// Fires when any element is clicked
|
|
'click': function (event) { ... },
|
|
|
|
// Fires when any element with the 'accept' class is clicked
|
|
'click .accept': function (event) { ... },
|
|
|
|
// Fires when 'accept' is clicked, or a key is pressed
|
|
'keydown, click .accept': function (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': function (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:
|
|
|
|
<dl class="objdesc">
|
|
{{#dtdd "type" "String"}}
|
|
The event's type, such as "click", "blur" or "keypress".
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "target" "DOM Element"}}
|
|
The element that originated the event.
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "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 of `target`, and its value changes as the
|
|
event bubbles.
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "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.
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "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.
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "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.
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "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.
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "isPropagationStopped()"}}
|
|
Returns whether `stopPropagation()` has been called for this event.
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "isImmediatePropagationStopped()"}}
|
|
Returns whether `stopImmediatePropagation()` has been called for this event.
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "isDefaultPrevented()"}}
|
|
Returns whether `preventDefault()` has been called for this event.
|
|
{{/dtdd}}
|
|
</dl>
|
|
|
|
Returning `false` from a handler is the same as calling
|
|
both `stopImmediatePropagation` and `preventDefault` on the event.
|
|
|
|
Event types and their uses include:
|
|
|
|
<dl class="objdesc">
|
|
{{#dtdd "<code>click</code>"}}
|
|
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 fire `click`.
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "<code>dblclick</code>"}}
|
|
Double-click.
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "<code>focus, blur</code>"}}
|
|
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.
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "<code>change</code>"}}
|
|
A checkbox or radio button changes state. For text fields, use
|
|
`blur` or key events to respond to changes.
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "<code>mouseenter, mouseleave</code>"}} The pointer enters or
|
|
leaves the bounds of an element. These events do not bubble.
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "<code>mousedown, mouseup</code>"}}
|
|
The mouse button is newly down or up.
|
|
{{/dtdd}}
|
|
|
|
{{#dtdd "<code>keydown, keypress, keyup</code>"}}
|
|
The user presses a keyboard key. `keypress` is most useful for
|
|
catching typing in text fields, while `keydown` and `keyup` can be
|
|
used for arrow keys or modifier keys.
|
|
{{/dtdd}}
|
|
</dl>
|
|
|
|
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.
|
|
|
|
{{/api_box_inline}}
|
|
|
|
<h2 id="timers"><span>Timers</span></h2>
|
|
|
|
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.
|
|
You'll get an error if you call the native function.
|
|
|
|
{{> api_box setTimeout}}
|
|
{{> api_box setInterval}}
|
|
{{> api_box clearTimeout}}
|
|
{{> api_box clearInterval}}
|
|
|
|
<h2 id="meteor_deps"><span>Meteor.deps</span></h2>
|
|
|
|
Meteor has a simple dependency tracking system, so that it it can
|
|
automatically rerender templates and such when [`Session`](#session)
|
|
variables are modified, or database queries 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
|
|
(say, a database query), it automatically saves the current
|
|
"invalidation context" object if any (say, the current template being
|
|
rendered.) Later, when the data changes, it can "invalidates" this
|
|
context (tell the template to rerender itself.) The whole
|
|
implementation is about 50 lines of code.
|
|
|
|
Developers, particularly package authors, can use *invalidation
|
|
contexts* to implement additional reactive data sources or to write
|
|
functions that automatically register dependencies on reactive data
|
|
sources.
|
|
|
|
{{> api_box Context }}
|
|
|
|
Create an invalidation context by calling this constructor, then run
|
|
some code inside the context with [`run`](#run). Finally, register a
|
|
callback with [`on_invalidate`](#on_invalidate) that will get called
|
|
when the code you run wants to signal that it should be rerun.
|
|
|
|
Code can see if it's running inside an invalidation context by reading
|
|
the [`Meteor.deps.Context.current`](#current) global variable, which
|
|
will be the currently active context, or `null` if it's not being run
|
|
from inside a context. If it wants to participate in the reactivity
|
|
system, it should save this context away, and later call the
|
|
[`invalidate`](#invalidate) method on the context when it wants to
|
|
signal that something has changed. If it does this, it should also use
|
|
[`on_invalidate`](#on_invalidate) to set up a cleanup function so that
|
|
it can know when to stop listening for changes.
|
|
|
|
Invalidation contexts have an attribute `id` which is a unique positive
|
|
integer. You're free to add any other attributes you like to the
|
|
invalidation context for your own convenience, as long as they don't
|
|
start with an underscore.
|
|
|
|
{{> api_box run }}
|
|
|
|
This function simply sets [`Meteor.deps.Context.current`](#current) to
|
|
this invalidation context, runs `func`, and then restores it to its
|
|
previous value. It returns the result of calling `func`.
|
|
|
|
It's fine for `run` to be called recursively. `current` will return the
|
|
innermost context.
|
|
|
|
{{> api_box on_invalidate }}
|
|
|
|
If this context hasn't been invalidated yet, adds `callback` to the list
|
|
of callbacks that will be called when [`invalidate`](#invalidate) is
|
|
called. If the context has already been invalidated, call `callback`
|
|
immediately.
|
|
|
|
Typically this function will have two kinds of callers:
|
|
|
|
* The function that creates the invalidation context will use the
|
|
`on_invalidate` callback as a signal to rerun the code in the context,
|
|
to see what new value it returns. In order to rerun the code, it'll
|
|
create a fresh invalidation context and reregister its `on_invalidate`
|
|
callback on that new context. When that context is invalidated the
|
|
cycle will repeat.
|
|
|
|
* Functions that are sources of reactive data will save
|
|
[`Meteor.deps.Context.current`](#current) into some kind of list of
|
|
listeners. They'll use the `on_invalidate` callback to remove the
|
|
context from their listener list.
|
|
|
|
Example:
|
|
|
|
// Print the current username to the console. Will re-run every time
|
|
// the username changes.
|
|
var log_current_username = function () {
|
|
var update = function () {
|
|
var ctx = new Meteor.deps.Context(); // invalidation context
|
|
ctx.on_invalidate(update); // rerun update() on invalidation
|
|
ctx.run(function () {
|
|
var username = Session.get("username");
|
|
console.log("The current username is now", username);
|
|
});
|
|
};
|
|
update();
|
|
};
|
|
|
|
// Example use. Since Session is reactive (meaning that it knows how
|
|
// to use Meteor.deps to record its dependencies), log_current_username
|
|
// will be re-run whenever Session.set is called for "username".
|
|
Session.set("username", "matt");
|
|
log_current_username(); // prints matt
|
|
Session.set("username", "geoff"); // immediately prints geoff
|
|
Session.set("username", "geoff"); // won't print: Session won't trigger
|
|
// invalidation if the value is the same.
|
|
|
|
{{> api_box invalidate }}
|
|
|
|
If this function has already been called on this context, it does
|
|
nothing (a mathematician would say that it is "idempotent.") Otherwise
|
|
it calls each [`on_invalidate`](#on_invalidate) function registered on
|
|
the context.
|
|
|
|
The functions aren't called immediately — instead, they will be
|
|
called the next time you call [`Meteor.flush`](#meteor_flush). This function
|
|
just adds the context to the flush list and is guaranteed to do nothing
|
|
else just yet.
|
|
|
|
If you don't call [`Meteor.flush`](#meteor_flush) explicitly, it will be called
|
|
for you automatically when your code is done running (by setting a
|
|
`setTimeout` timer with a delay of zero.)
|
|
|
|
Example:
|
|
|
|
// Create a simple class called Weather that tracks the current
|
|
// temperature. The temperature can be read reactively.
|
|
var Weather = function () {
|
|
this.temperature = 60;
|
|
this.listeners = {};
|
|
};
|
|
|
|
// Function to get the temperature (and, if called in a reactive
|
|
// context, start listening for changes to the temperature.)
|
|
Weather.prototype.get_temp = function () {
|
|
var context = Meteor.deps.Context.current;
|
|
|
|
// If we're inside a context, and it's not yet listening to
|
|
// temperature changes..
|
|
if (context && !this.listeners[context.id]) {
|
|
// .. add it to our list of contexts that care about the temperature ..
|
|
this.listeners[context.id] = context;
|
|
|
|
// .. and remember to take it off our list when it goes away.
|
|
var self = this;
|
|
context.on_invalidate(function () {
|
|
delete self.listeners[context.id];
|
|
});
|
|
}
|
|
|
|
// return the current temperature, whether or not in a reactive context.
|
|
return this.temperature;
|
|
};
|
|
|
|
// Function to set the temperature, and notify anyone that might be
|
|
// listening for temperature updates.
|
|
Weather.prototype.set_temp = function (new_temp) {
|
|
if (this.temperature === new_temp)
|
|
return; // don't want to trigger invalidation if there's no change.
|
|
|
|
// Set the temperature
|
|
this.temperature = new_temp;
|
|
|
|
// Notify any contexts that care about temperature changes
|
|
for (var context_id in this.listeners)
|
|
// This will trigger the on_invalidate function above, but not
|
|
// immediately -- only when Meteor.flush() is called, or at the end
|
|
// of the event loop. So we know that this.listeners will be
|
|
// emptied, but it won't change while we're trying to loop over it.
|
|
this.listeners[context_id].invalidate();
|
|
};
|
|
|
|
{{> api_box current }}
|
|
|
|
This is a global variable that is set by [`run`](#run).
|
|
|
|
If you have a background in Lisp or programming language theory, you
|
|
might think of it as a dynamically scoped ("special") variable. (That
|
|
just means that [`run`](#run) sets it, runs some user-supplied code, and
|
|
then restores its previous value.)
|
|
|
|
|
|
<h2 id="meteor_http"><span>Meteor.http</span></h2>
|
|
|
|
`Meteor.http` provides an HTTP API on the client and server. To use
|
|
these functions, add the HTTP package to your project with `meteor add
|
|
http`.
|
|
|
|
{{> api_box httpcall}}
|
|
|
|
This function initiates an HTTP request to a remote server. It returns
|
|
a result object with the contents of the HTTP response. The result
|
|
object is detailed below.
|
|
|
|
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. 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()`](#method_unblock) to allow other methods 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.
|
|
|
|
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. The result object is always
|
|
defined. When run in synchronous mode, the `result` is returned from the
|
|
function, and the `error` value is a stored as a property in `result`.
|
|
|
|
Contents of the result object:
|
|
|
|
<dl class="objdesc">
|
|
|
|
<dt><span class="name">statusCode</span>
|
|
<span class="type">Number</span></dt>
|
|
<dd>Numeric HTTP result status code, or null on error.</dd>
|
|
|
|
<dt><span class="name">content</span>
|
|
<span class="type">String</span></dt>
|
|
<dd>The body of the HTTP response as a string.</dd>
|
|
|
|
<dt><span class="name">data</span>
|
|
<span class="type">Object or null</span></dt>
|
|
<dd>If the response headers indicate JSON content, this contains the body of the document parsed as a JSON object.</dd>
|
|
|
|
<dt><span class="name">headers</span>
|
|
<span class="type">Object</span></dt>
|
|
<dd>A dictionary of HTTP headers from the response.</dd>
|
|
|
|
<dt><span class="name">error</span>
|
|
<span class="type">Error</span></dt>
|
|
<dd>Error object if the request failed. Matches the `error` callback parameter.</dd>
|
|
|
|
|
|
</dl>
|
|
|
|
Example server method:
|
|
|
|
Meteor.methods({check_twitter: function (user_id) {
|
|
this.unblock();
|
|
var result = Meteor.http.call("GET", "http://api.twitter.com/xxx",
|
|
{params: {user: user_id}});
|
|
if (result.statusCode === 200)
|
|
return true
|
|
return false;
|
|
}});
|
|
|
|
Example asynchronous HTTP call:
|
|
|
|
Meteor.http.call("POST", "http://api.twitter.com/xxx",
|
|
{data: {some: "json", stuff: 1}},
|
|
function (error, result) {
|
|
if (result.statusCode === 200) {
|
|
Session.set("twizzled", true);
|
|
}
|
|
});
|
|
|
|
|
|
{{> api_box http_get}}
|
|
{{> api_box http_post}}
|
|
{{> api_box http_put}}
|
|
{{> api_box http_del}}
|
|
|
|
|
|
{{/better_markdown}}
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<template name="api_box">
|
|
<div class="api {{bare}}">
|
|
<h3 id="{{id}}">
|
|
<a class="name selflink" href="#{{id}}">{{{name}}}</a>
|
|
{{#if locus}}
|
|
<span class="locus">{{locus}}</span>
|
|
{{/if}}
|
|
</h3>
|
|
|
|
<div class="desc">
|
|
{{#each descr}}{{#better_markdown}}{{{this}}}{{/better_markdown}}{{/each}}
|
|
</div>
|
|
|
|
{{#if args}}
|
|
<h4>Arguments</h4>
|
|
{{> api_box_args args}}
|
|
{{/if}}
|
|
|
|
{{#if options}}
|
|
<h4>Options</h4>
|
|
{{> api_box_args options}}
|
|
{{/if}}
|
|
|
|
{{#if body}}
|
|
{{#better_markdown}}{{{body}}}{{/better_markdown}}
|
|
{{/if}}
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<template name="api_box_args">
|
|
<dl class="args">
|
|
{{#each this}}
|
|
<dt><span class="name">{{{name}}}</span>
|
|
<span class="type">
|
|
{{#if type_link}}
|
|
<a href="#{{type_link}}">{{type}}</a>
|
|
{{else}}
|
|
{{type}}
|
|
{{/if}}
|
|
</span></dt>
|
|
<dd>{{#better_markdown}}{{{descr}}}{{/better_markdown}}</dd>
|
|
{{/each}}
|
|
</dl>
|
|
</template>
|
|
|
|
|
|
<template name="api_section_helper">
|
|
<h2 id="{{id}}"><a href="#{{id}}" class="selflink"><span>{{name}}</span></a></h2>
|
|
</template>
|
|
|
|
|