diff --git a/docs/client/api.html b/docs/client/api.html index 1f9eaec93c..41d091712e 100644 --- a/docs/client/api.html +++ b/docs/client/api.html @@ -59,45 +59,47 @@ will publish that cursor's documents. return Rooms.find({admin: this.userId}, {fields: {secretInfo: 1}}); }); -Otherwise, the publish function can [`set`](#publish_set) and -[`unset`](#publish_unset) individual record attributes on a client. These -methods are provided by `this` in your publish function. +Otherwise, the publish function should call the functions +[`added`](#publish_added) (when a new document is added to the published record +set), [`changed`](#publish_changed) (when some fields on a document in the +record set are changed or cleared), and [`removed`](#publish_removed) (when +documents are removed from the published record set) to inform subscribers about +documents. These methods are provided by `this` in your publish function. + + -In particular, if you use [`observe`](#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 initializing = true; var handle = Messages.find({roomId: roomId}).observe({ - added: function (doc, idx) { + added: function (doc) { count++; - self.set("counts", uuid, {roomId: roomId, count: count}); - self.flush(); + if (!initializing) + self.changed("counts", roomId, {count: count}); }, - removed: function (doc, idx) { + removed: function (doc) { count--; - self.set("counts", uuid, {roomId: roomId, count: count}); - self.flush(); + self.changed("counts", roomId, {count: count}); } // don't care about moved or changed }); // Observe only returns after the initial added callbacks have - // run. Now mark the subscription as ready. + // run. Now return an initial value and mark the subscription + // as ready. + initializing = false; + self.added("counts", roomId, {count: count}); self.complete(); - self.flush(); - // stop observing the cursor when client unsubs + // Stop observing the cursor when client unsubs. + // Stopping a subscription automatically takes + // care of sending the client any removed messages. self.onStop(function () { handle.stop(); }); @@ -112,7 +114,9 @@ Example: }); // client: use the new collection - console.log("Current room has " + Counts.findOne().count + " messages."); + console.log("Current room has " + + Counts.findOne(Session.get("roomId")).count + + " messages."); {{#warning}} Meteor will emit a warning message if you call `Meteor.publish` in a @@ -125,10 +129,10 @@ will still work. This is constant. However, if the logged-in user changes, the publish function is rerun with the new value. -{{> api_box subscription_set}} -{{> api_box subscription_unset}} +{{> api_box subscription_added}} +{{> api_box subscription_changed}} +{{> api_box subscription_removed}} {{> api_box subscription_complete}} -{{> api_box subscription_flush}} {{> api_box subscription_onStop}} @@ -139,12 +143,13 @@ is the place to stop the observes. {{> 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 +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](#meteor_collection), with the same name as the `collection` -argument to `set`. Meteor will queue incoming attributes until you -declare the [`Meteor.Collection`](#meteor_collection) on the client with -the matching collection name. +argument used in the publish handler's `added`, `changed`, and `removed` +callbacks. Meteor will queue incoming attributes until you declare the +[`Meteor.Collection`](#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" @@ -155,11 +160,14 @@ the matching collection name. ... 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.) +The client will see a document if the document is currently in the published +record set for any of its subscriptions. + +If more than one subscription sends conflicting values for a field (same +collection name, document ID, and field name), then the value on the client will +be one of those values. Try not to define multiple publishers that disagree on +field values; fortunately, this never occurs if you just return cursor from a +publish handler. If you call [`Meteor.subscribe`](#meteor_subscribe) within a [reactive context](#reactivity) such as [`Meteor.autorun`](#meteor_autorun), the @@ -180,12 +188,6 @@ messages. When you change rooms by calling `Session.set("current-room", unsubscribe from the original room's chat messages, and continue to stay subscribed to your private messages. -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}); -

Methods

Methods are remote functions that Meteor clients can invoke. @@ -2542,5 +2544,3 @@ by spammers.) - - diff --git a/docs/client/api.js b/docs/client/api.js index 310e347522..70b30c00c7 100644 --- a/docs/client/api.js +++ b/docs/client/api.js @@ -80,44 +80,61 @@ Template.api.publish = { ] }; -Template.api.subscription_set = { - id: "publish_set", - name: "this.set(collection, id, attributes)", +Template.api.subscription_added = { + id: "publish_added", + name: "this.added(collection, id, fields)", locus: "Server", - descr: ["Call inside the publish function. Queues a command to set attributes."], + descr: ["Call inside the publish function. Informs a subscriber that a document has been added to the published set."], args: [ {name: "collection", type: "String", - descr: "The name of the collection that should be affected." + descr: "The name of the collection that contains the new document." }, {name: "id", type: "String", - descr: "The ID of the document that should be affected." + descr: "The new document's ID." }, - {name: "attributes", + {name: "fields", type: "Object", - descr: "Dictionary of attribute keys and their values." + descr: "The fields in the new document. `_id`, if provided, is ignored." } ] }; -Template.api.subscription_unset = { - id: "publish_unset", - name: "this.unset(collection, id, keys)", +Template.api.subscription_changed = { + id: "publish_changed", + name: "this.changed(collection, id, fields)", locus: "Server", - descr: ["Call inside the publish function. Queues a command to unset attributes."], + descr: ["Call inside the publish function. Informs a subscriber that a document has been modified in the published set."], args: [ {name: "collection", type: "String", - descr: "The name of the collection that should be affected." + descr: "The name of the collection that contains the changed document." }, {name: "id", type: "String", - descr: "The ID of the document that should be affected." + descr: "The changed document's ID." }, - {name: "keys", - type: "Array", - descr: "Array of attribute keys." + {name: "fields", + type: "Object", + descr: "The fields in the document to change, mapped to their new values. Fields that are not present in `fields` are unchanged; fields that are present in `fields` but whose value is `undefined` are cleared. `_id`, if provided, is ignored." + } + ] +}; + +Template.api.subscription_removed = { + id: "publish_removed", + name: "this.removed(collection, ids)", + locus: "Server", + descr: ["Call inside the publish function. Informs a subscriber that some documents have been removed from the published set."], + args: [ + {name: "collection", + type: "String", + descr: "The name of the collection that documents are being removed from." + }, + {name: "ids", + type: "Array of Strings", + descr: "The IDs of the documents that are being removed." } ] }; @@ -126,15 +143,9 @@ Template.api.subscription_complete = { id: "publish_complete", name: "this.complete()", locus: "Server", - descr: ["Call inside the publish function. Queues a command to mark this subscription as complete (initial attributes are set)."] + descr: ["Call inside the publish function. Informs the subscriber that an initial set of documents has been added to the record set."] }; -Template.api.subscription_flush = { - id: "publish_flush", - name: "this.flush()", - locus: "Server", - descr: ["Call inside the publish function. Sends all the pending set, unset, and complete messages to the client."] -}; Template.api.subscription_stop = { id: "publish_stop", @@ -1478,4 +1489,3 @@ Template.api.email_send = { } ] }; - diff --git a/docs/client/docs.js b/docs/client/docs.js index f854c18bff..be5728d747 100644 --- a/docs/client/docs.js +++ b/docs/client/docs.js @@ -101,10 +101,10 @@ var toc = [ "Publish and subscribe", [ "Meteor.publish", [ {instance: "this", name: "userId", id: "publish_userId"}, - {instance: "this", name: "set", id: "publish_set"}, - {instance: "this", name: "unset", id: "publish_unset"}, + {instance: "this", name: "added", id: "publish_added"}, + {instance: "this", name: "changed", id: "publish_changed"}, + {instance: "this", name: "removed", id: "publish_removed"}, {instance: "this", name: "complete", id: "publish_complete"}, - {instance: "this", name: "flush", id: "publish_flush"}, {instance: "this", name: "onStop", id: "publish_onstop"}, {instance: "this", name: "stop", id: "publish_stop"} ],