Graceful page transitions with latency and Iron Router?

I recently moved away from autopublish and have been trying to update my application to gracefully deal with the latency introduced by this change. I have been using a combination of template and router level subscriptions. The template level subscriptions work beautifully but I have been having issues with the router level subscriptions.

I am doing router level subscriptions in the subscriptions function of the route and I often populate the data function with documents from these subscriptions. I don’t want to render the page before the subscriptions are ready, because then I would have to check that the subscriptions are ready in whenever I access a document from those subscriptions.

The standard solution seems to be to either use a waitOn or to manually check this.ready before rendering anything in the router.

action: function() {
	    if (!this.ready())
		this.render('loading');
	    else
	        this.render();
	 }

However, this creates undesirable page flickering if it only takes a second to load the subscriptions (i.e. the user will click a link, the loading screen will show for ~.1 seconds, and then the new page is loaded).

Another solution, which I personally prefer, is to not leave the current page until the subscriptions for the next page are ready.

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

But this has a whole other set of issues. For example, if the route for the next page is missing a subscription that the current page needs, then the current page will re-render and will of course throw an exception because it is missing data. For example, suppose the current route looks like:

Router.route('/projects/:projectID', {
    name: 'projectOverview',
    action: function() {
        if (!this.ready())
            return;
        else
            this.render();
    }
    subscriptions: function() {
        return [Meteor.subscribe('project', this.params.projectID)];
    },
    data: function() {
        return {project: Projects.findOne(this.params.projectID)};
    }
);

<template name="projectOverview">
    {{project.name}}
    <a href="{{pathFor route="tasksOverview"}}">Tasks Overview</a>
</template>

and that the new route (after you click the Tasks Overview link) is:

Router.route('/tasks', {
    name: 'tasksOverview',
    action: function() {
        if (!this.ready())
            return;
        else
            this.render();
    }
    subscriptions: function() {
        return [Meteor.subscribe('tasks')];
    },
    data: function() {
        return {tasks: Tasks.find()};
    }
);

<template name="tasksOverview">
    You have {{tasks.count()}} tasks
</template>

Then after you click the link in the first route, you would get an error that project is undefined when you try to access project.name. This error happens because as soon as you click the link, the first route is torn down and the new one is created, so the subscriptions maintained by the first route are also torn down. And so project is no longer available.

Ideally, I would like for there to be a way for the old subscriptions and data context to not get torn down until the new ones are ready. But I cannot think of a good way to make that happen.

I feel like this is a problem that basically everyone that uses Meteor has to deal with, so I am curious what solutions people have come up with.

maybe some inspiration how to mask few miliseconds between transitions http://www.webtempest.com/meteorjs-animation

Won’t the subscriptions on the old page still expire, causing the old page to re-render during the animation?

I have not been in similar position, as I am not very big fan of router subscriptions.
So I dont want to waste your time pointing to not working steps.
1 more question is in my mind now, how collection.find with reactive: false in template handle removed subscription, can it freeze it too ?

Nope, an error is still thrown, unfortunately. I think that the whole template might be being re-rendered, not just portions that reference project. Don’t totally understand why…

Out of curiosity, if you don’t use router subscriptions do you entirely rely upon template level subscriptions? And if so, doesn’t it get annoying to constantly check if your subscriptions are ready in the template helpers?

Hello 2015 @veered! Router level subscriptions + a subscription caching manager will mostly fix this problem.

Old me cannot benefit from an answer 4 years late, but hopefully posterity will…

2 Likes