Search code examples
javascriptmeteoriron-router

Meteor - iron-router not waiting on subscription data in onBeforeAction hook


I want to set a Session variable (artistNotAvailable) when the requested artist is not available. Unfortunately, the route does not work, because it is not waiting on subscription data in my onBeforeAction hook. artistAvail and artist is undefined, but not because there is no artist in the DB, I think it is a subscription problem. I debugged it and calling Artists.find().fetch(); in the browsers console returned undefined.

Here is my route:

this.route('eventPage', {
        path: '/event/:slug/:openDate?/:closeDate?',
        onBeforeAction: [teamFilter, function() {
            var event = this.data();
            if (event.outdoor) {
                this.subscribe('artists', this.params.slug);
                if (this.ready()) {
                    var artistAvail = Artists.findOne({eventId: event._id, openDate: moment(this.params.openDate).toDate(), closeDate: moment(this.params.closeDate).toDate()});
                    if ((!this.params.openDate && !this.params.closeDate) || typeof artistAvail === "undefined") {
                        var artist = Artists.findOne({
                            eventId: event._id,
                            openDate: {$lte: new Date()},
                            closeDate: {$gte: new Date()}
                        });
                        if (Artists.find().count() > 0 && artist) {
                            Session.set('artistNotAvailable', true);
                            this.redirect('eventPage', {
                                slug: this.params.slug,
                                openDate: moment(artist.openDate).format('YYYY-MM-DD'),
                                closeDate: moment(artist.closeDate).format('YYYY-MM-DD')
                            });
                        } else {
                            Session.set('noArtists', true);
                            this.redirect('overviewPage', {slug: this.params.slug});
                        }
                    } else {
                        this.subscribe('musicOutdoor', this.params.slug, moment(this.params.openDate).toDate(), moment(this.params.closeDate).toDate());
                        if (this.ready()) {
                            var guestsIds = new Array();
                            Guests.find({artistId: artistAvail._id}).forEach(function (guest) {
                                guestIds.push(guest._id);
                            });
                            this.subscribe('guestsOutdoor', guestIds);
                        } else {
                            this.render('loading');
                        }
                    }
                } else {
                    this.render('loading');
                }
            } else {
                this.subscribe('musicIndoor', this.params.slug);
                this.subscribe('guestsIndoor', this.params.slug);
                if (!this.ready()) {
                    this.render('loading');
                }
                this.next();
            }
            this.next();
        }],
        waitOn: function() { return [Meteor.subscribe('singleEvent', this.params.slug)]; },
        data: function() {
            return Events.findOne({slug: this.params.slug});
        }
    });

Subscription:

Meteor.publish('artists', function(slug) {
    var event = Events.findOne({slug: slug});
    if (event) {
        return Artists.find({eventId: event._id});
    } else {
        return null;
    }
}); 

Now the problem is that when I access the eventPage with a wrong openDate or closeDate I will be redirected to the overviewPage, even though there are artists in the db. As already mentioned, I debugged it and it seems to be that this.ready() is not working. I really miss .wait() :-(

Any help would be greatly appreciated.


Solution

  • Iron Router works fine.

    this.subscribe is like Meteor.subscribe and Iron-Router doesn't wait for this.

    waitOn is the function that will wait until each of your returned subscriptions are ready that is why this.ready() is true in onBeforeAction

    There are several ways of doing what you want

    • You could do it like CodeChimp said by using templates with create/destroyed
    • You could split your route in different routes so that you redirect when it's needed
    • you could use .wait() from the new API of iron router here.