Don't use afterModel for redirection

09 February 2018

An advantage about going through my book for a rewrite is that I
am inclined to review things I wouldn’t when doing simple version upgrades.
In the below post I want to show you one of the things I learned this way.

Redirecting during a route transition

If you want to redirect your app to another route while you’re already in the
middle of a transition, there are two scenarios.

If you don’t need the resolved model

If you don’t need to resolve the model to decide whether to redirect (or where
to redirect), you should put the redirection in the beforeModel hook which is
the first one to run. The classic example is protecting an authenticated route:

If you need the resolved model

If you need to know what the model is to be able to decide on the redirection,
you need a hook that runs after the model hook. I’ve so far used the
afterModel hook for this purpose that gets passed the resolved model.

You can see that the first transition, to bands.band.index, is aborted because
of the this.transitionTo in the afterModel of the bands.band route and
then a new one is attempted to bands.band.details. However, all three model
hooks are run again for the bands.band route (see lines 8-11).

Also note that there are two ajax requests going out. The
store.findRecord('band', ...) call is responsible for this, as it will fetch
the band from the backend (in the background if it has found it in the store so
as not to block page rendering).

Since the model hook of the bands.band route was fired twice, the ajax request
is fired twice, too.

… so use the redirect hook

There is another, possibly less known route hook called redirect, which is
more suitable for redirection. I know, who would’ve thought, right?

I thought it was basically an alias for afterModel, but there is a very
important difference in their behavior. The source code shines a light on this
distinction (see here):

redirect and afterModel behave very similarly and are called almost at the
same time, but they have an important distinction in the case that, from one of
these hooks, a redirect into a child route of this route occurs: redirects from
afterModel essentially invalidate the current attempt to enter this route, and
will result in this route’s beforeModel, model, and afterModel hooks being
fired again within the new, redirecting transition. Redirects that occur within
the redirect hook, on the other hand, will not cause these hooks to be fired
again the second time around; in other words, by the time the redirect hook
has been called, both the resolved model and attempted entry into this route are
considered to be fully validated.

The model hooks for bands.band are not fired a second time, and so there is
only one ajax request hitting the backend and less time spent in model hooks
(and consequently the page can be rendered faster).

So, in summary, don’t use the afterModel for redirection. Use redirect.