Search code examples
meteoriron-router

Meteor ironrouter - A collection returns undefined even though I am calling waitOn()


Update: This has been solved and the code amended to reflect the changes I added. I also strongly recommend reading the comment below this post. Some changes are coming in IronRouter we need to be mindful of.

The crucial thing is to add the following to your data function:

if(!this.ready()) {
    return;
}

I am having an issue with IronRouter in my application. The code is below:

/** 
 *  Project list view (all projects) with optional 
 *  filter parameter for showing projects only by 
 *  their category name.
 */ 
this.route('list', {
    path: '/:_category_slug?',
    template: 'template_main',
    action: function() {
        if(this.ready()) {
            this.render();
        }
    },
    waitOn: function() {
        return [
            Meteor.subscribe('projects'), 
            Meteor.subscribe('formations'),
            Meteor.subscribe('categories')
        ];
    },
    data: function() {
        if(!this.ready()) {
            return;
        }

        if(this.params._category_slug) {
            /**
             * Building up the query given the category slug and the language
             */
            var query = {};
            query['slug.' + App.language] = this.params._category_slug;

            /**
             *  Grab the category given the query
             */
            var category = App.models.categories.findOne(query);

            console.log(category);

            return App.models.projects.find({}).fetch();

        }
        else {
            return App.models.projects.find({}).fetch();
        }
    },
    yieldTemplates: {
        'components_header': {to: 'header'},
        'views_list': {to: 'content'},
        'components_footer': {to: 'footer'}
    }
});

What I am trying to do is get the category from the category slug so I can access its ID, which I need for another query.

The problem is, when I reload the page and the path given above is matched, this route seems to be run three times, and the first time, logging the category variable on the console returns undefined, and then another two times, the actual category is printed out.

I would expect that the waitOn() function would have populated all categories by the time I reach the data function, so I can access my category data with the query the first time around, but this is not happening.

Can anyone see anything glaringly obvious in my code that could be causing this issue, and why is the route being run three times?

I am using the latest version of IronRouter (iron:router@0.9.3) and Meteor (METEOR@0.9.2.2).


Solution

  • When using iron:router <= 0.9.3 you have to activate the default loading hook in order to get the expected behavior of WAITING for the subscriptions to be ready before rendering the templates.

    Add this in your router configuration code :

    Router.onBeforeAction("loading");
    

    This means you no longer have to provide an action function doing the waiting logic (rendering your templates only when the WaitList is ready).

    However, the data function will still get called initially when subscriptions are not ready, so you have to do the check yourself :

    data:function(){
      if(!this.ready()){
        return;
      }
      // return actual data when ready
    }
    

    A lot of questions about iron:router have surfaced regarding this loading hook behavior, and to be fair it's true that it is catchy because when you use waitOn, you expect your RouteController to actually WAIT ON those subscriptions before displaying templates, right ?

    This is why in the latest "unstable" release of iron:router@1.0.0-pre2, the loading hook is automatically added for you when it detects you're using waitOn.

    I strongly advise you to switch to iron:router@1.0.0-pre2 to get familiar with the newest API, it features a complete rewrite and nice docs which are up-to-date.

    https://github.com/iron-meteor/iron-router/blob/devel/Guide.md

    It is mostly backward compatible with a few gotchas, notably it requires you to define all your routes along with RouteControllers in the lib/ folder so that it is available to both the client and server.