To set the context, this is the use of Template subscriptions together with Template autorun in the onRendered function.
The official documentation suggests this form:
Template.something.onRendered(function() {
var self = this;
self.autorun(function() {
self.subscribe("name", function() {
var thing = Collection.findOne(); // some reactive operation
// do fun stuff with thing
});
});
Which unsubscribes/resubscribes to the name publication reactively.
And that works very nicely. However I have used this form:
Template.something.onRendered(function() {
var self = this;
self.subscribe("name", function() {
self.autorun(function() {
var thing = Collection.findOne(); // some reactive operation
// do fun stuff with thing
});
});
Which also works very nicely - and feels more ârightâ to me. Subscribe only once and let reactivity do its thing.
I think you would use the first snippet over the second when you have reactive arguments that you pass into the subscription call. Otherwise I think it makes no difference.
That does make sense, but when you say âno differenceâ, surely there is more overhead in unsubscribing and resubscribing - or is that ignored because the subscriptionâs not actually changed?
I would say that you should prefer the 2nd form if you donât have reactive arguments to the subscription, whether or not Meteor figures out on its own if it actually needs to un-/resubscribe instead of just staying suscribed. Whether it does already figure that out I donât know.
The reason for preferring the 2nd form is (obviously?) that stuff that doesnât need to rerun shouldnât have to, i.e. proper scoping / structure of code that aligns with what behavior is actually desired. EDIT: I suppose thatâs why the 2nd form feels better to you as well.
If you call Meteor.subscribe within a reactive computation, for example using Tracker.autorun, the subscription will automatically be cancelled when the computation is invalidated or stopped; itâs not necessary to call stop on subscriptions made from inside autorun. However, if the next iteration of your run function subscribes to the same record set (same name and parameters), Meteor is smart enough to skip a wasteful unsubscribe/resubscribe.
Iâm currently using Iron Router for subscriptions, but Iâm slowly migrating to Template subscriptions. This is how Iâm doing it so far:
Template.template_name.onCreated(function() {
var instance = this;
instance.state = new ReactiveDict;
instance.autorun(function() {
var subscription1 = instance.subscribe("Collection_Name1");
var subscription2 = instance.subscribe("Collection_Name2", Session.get('session_var'));
if (subscription1.ready()) {
var record = instance.document();
// Reactive vars
if (record) {
instance.state.set('reactive_var', record.field);
} else {
instance.state.set('reactive_var', null);
}
}
});
instance.count = function() {
return Collection_Name1.find({}).count();
}
instance.document = function() {
return Collection_Name1.findOne({
_personId: Meteor.userId()
});
}
});
Template.template_name.helpers({
setFormMode: function() {
var count = Template.instance().count();
var data_set = Template.instance().document();
if (count === 0) return {
doc: null,
type: "insert"
};
else if (data_set) return {
doc: data_set,
type: "update"
};
}
});
Will someone please review this for correctness? What would you do differently?
For example,
Whatâs so wrong with putting the subscription1 inside of autorun; will I still get updates to subscription1 data if this is outside autorun? How would you do it?
Why but the subscriptions in onRendered vs onCreated and vis-versa?
I use instance.document to access query the published cursor, and is used by the helper methods. What would you do?
I havenât tested this, but instead of if (subscription1.ready())), try if (instance.subscriptionsReady()). This will cover all the subscriptions your template is waiting for.
Putting subscription1 inside an autorun is useless (it will even cause a (very minor) overhead). A subscription doesnât need an autorun to update the data.
subscriptions2, on the other side, needs an autorun, because one of its arguments might change reactively.
You usually put subscriptions in onCreated, so that they are run as soon as possible and while the initial DOM is built. There is usually no need to wait for onRendered.
I wouldnât do that. I think your collection access functions belongs with the collection, not with the template:
.API is a bit awkward, but I do like the general idea of this. I say âawkwardâ because we generally donât put âwhat something isâ into âthe name we call itâ, e.g. I say âmy macbookâ, not âmy macbook laptop personal computerâ, even though my MacBook is indeed a laptop / personal computer. 50% of programming (or maybe 33%) is finding really good names for things, or at least avoiding the absolutely terrible ones, and calling an API âsomething something APIâ is not mega terrible, but easy enough to improve â and very easy to spot, too.
I understand that youâve probably just been using ANY name for that, but Iâm just stating this because such things actually happen in real code, and itâs good to pay attention to it. AND, as I said, I really like this idea of extending the standard collection API with our own, âuser-definedâ methods, and Iâm trying to think of a proper namespace to put them in for myself.
Maybe .ext could work, like Meteor.users.ext.findAdminUsers(), Products.ext.findNewAdditions(), Threads.ext.archiveOlderThan(30, 'days')âŚ
Cool, thanks for linking that. Currently really getting into the depths of Meteor development and good to see thoughts on structure, organization etc from others whoâre also spending lots of time working in and thinking about Meteor! (Are you part of percolate? I donât really know most of the people here on the forums, begun participating only a week or so back!)
EDIT: I suppose this message was a bit off-topic. Feel free to respond in a PM if you like, thatâs probably more appropriate
If I donât put subscription1 inside a autorun, the âreactive_varâ reactive variable will not get set because the ready() will not get called on this publication. Or another way, If I want ready() to get called and set the reactive var, I need it inside a autorun from what I found.
A reason why you might want your subscription inside the autorun is if itâs subscribing based on reactive parameters. A common example would be paginating a publication with a limit parameter.
In that case, you do want the subscription to re-run every time that parameter changes, so Iâm pretty sure you would put it inside the autorun.
+1 but @aadams do not use log in/out - so publish seems not to re-run. Or you can confirm that Meteor.connection.setUserId(userId) works like log in/out?