iron-meteor / iron-router

A client and server side router designed specifically for Meteor.
MIT License
1.98k stars 413 forks source link

onRendered functions called before subscriptions in waitOn are ready #1464

Closed felberj closed 8 years ago

felberj commented 8 years ago

http://meteorpad.com/pad/crdqcPq9f76KDFwG6/Leaderboard

You will get 2 alerts. Alert is called in Template.inner.onRendered with the number of players it found. The numbers of players should both time be 6, as we waitOn it. But the first time it's 0.

dggriffin commented 8 years ago

I'm running into a similar issue. Information from the server (from within the waitOn) is indeed not fully injected before the onRendered is called.

MichaelJCole commented 8 years ago

You may find this interesting: https://github.com/iron-meteor/iron-router/issues/1044

MichaelJCole commented 8 years ago

Hey, I got this to work once I declared the template parameter explicitly.

I used this code, but it may also work with waitOn. (Edit: for me it also worked with waitOn)

Router.route('conference', {
  layoutTemplate: 'mainEmpty',
  template: 'conference',         // <-------------- this was the last change I made before it worked.
  path: '/c/:b/:opportunityId/',
  onAfterAction: function() {
    if (this.brand) document.title = this.brand().title;
  },
  data: function() {
    if(!this.ready()) return;
    return Opportunities.findOne(this.params.opportunityId);
  },
  subscriptions: function() {
    return Meteor.subscribe('opportunityById', this.params.opportunityId);
  },
  waitOn: undefined,  // unset defaults  defined on the router above.
  action: function() {
    if (this.ready()) return this.render();
    this.render('loading');
  }
});
felberj commented 8 years ago

doest not seem to work in my example that I posted

bimmlerd commented 8 years ago

Alright, here's how we fixed that problem:

The first important thing is to to include the action function like so:

action: function() {
    if (this.ready()) {
        this.render();
    }
}

That worked for almost everything, but we still had some issues. In our case, it was about templates that aren't rendered in using yield, and are thus out of Iron Router's control. Switch these over to content regions (using {{yield 'contentRegionName'}}) and then explicitly render them in the action function like so:

action: function() {
    if (this.ready()) {
        this.render();
        this.render('contentRegionTemplate', {to: 'contentRegionName'});
    }
}

You need these action functions, since the waitOn only means that the subs defined there will be added to a waitlist, but not that that waitlist will be waited on. Essentially, what happens now is that your action function is called twice, thanks to reactivity, and the templates are only rendered once the data is ready.