Question about ironRouter waitOn and action executing at odd time


#1

I may be just not understanding the flow here, but I noticed something that seemed strange. I put up a screencast and have the code on github.

I have my subscribe in the waitOn, and my .find in the action, of the Iron Router config. Then, if I have 2 browsers open to the same edit page, and save an edit in one page, I see that the waitOn and action methods run in the other browser. This seems unnecessary, as the reactivity is changing the text in the other browser anyway, so why do the waitOn and action methods run again?

Is there a good explanation of why this is happening?


#2

Basically everything in IronRouter is reactive, so if you have a reactive data source in either the action, the waitOn, the subscribe or the data function, a change to that source (Reactive Var, .find etc) will cause the route to re-run. As a general rule you should try to keep reactive sources out of IronRouter because otherwise you will get strange behaviour as you are seeing here. The quickest solution to the problem is to move the query for item out of the action and into a template helper, that way it won’t cause the entire route the rerun. Instead just pass the _id into the data function, since that is non-reactive and won’t cause a re-run.


#3

Thanks for the explanation!.. Yes, I did see an example once where the ID was passed through via the data, instead of the actual document… there are so many ways of accomplishing the same thing with meteor that I sometimes get into trouble! I actually found a completely different way to do this, and I’ll post the code tomorrow.


#4

Here’s what I ended up with:

Router.route('/book/:_id', {
  subscriptions: function () {
    var id = this.params._id;
    console.log("/book/:id subscriptions " + id);
    subs.subscribe('book', id);
  },
  data: function () {
    var id = this.params._id;
    console.log("/book/:id data," + id);
    return Books.findOne({_id: id});
  },
  name: 'book.show',
  template: 'editBook',
  onRun: function() {
    var id = this.params._id;
    console.log("on run, log a view of book " + id);
    this.next();
  }
}
);

I tried your suggesiton @entropy, of moving the find into the helper, and just passing the ID in the route data function, but then, instead of the router’s ‘data’ function executing when data changes in the database, instead the template’s ‘helper’ function executes when the data changes… and since each one of those functions is doing the exact same thing (ie. doing a Books.findOne()) I don’t see the difference.

But, the above solution helps me because I am using the ‘onRun’, which only runs once when the user enters the route, and doesn’t rerun when the data changes. Only the “data” function retuns when the data changes.