Create a gist now

Instantly share code, notes, and snippets.

@machty /borf.md
Last active Jun 16, 2016

What would you like to do?
Distinguishing between redirect/afterModel

Background

Right now, afterModel and redirect are almost aliases; specifically, the default implementation of Route#afterModel calls redirect. The only difference is that the return value of redirect() is not used in any way, so you can't, say, return a promise from redirect and expect the transition to pause, which you'd be able to do with afterModel.

Scumbag machty tried to deprecate redirect, was met with pushback, and removed the soft deprecation. Now he's wondering if they are semantically separate enough to keep both around.

afterModel is the last of promise-aware route-entry-validation hooks, which is to say that beforeModel, model, and afterModel allow you to return promises that pause the transition until they resolve, and if they reject (or transitionTo elsewhere), the transition gets aborted. I call them route-entry-validation hooks because one of their main jobs is to validate that the route in question can actually be entered at this time. Part of this validation is resolving the model.

Problem

It's not an uncommon use case for a parent route's afterModel hook to redirect into another one of its child routes, e.g. in an attempted transition into 'a.b.c', BRoute#afterModel redirects into 'a.b.other'. The problem is that it's ambiguous as to whether BRoute can be considered validated at this point; should its entry-validation model hooks be called again during the transition into 'a.b.other'? There are use cases in both directions, so...

Solution: Embrace redirect as (slightly) semantically different

  1. Change the default implementation of afterModel to just be an empty function.
  2. Have router.js synchronously call redirect after afterModel fulfills. The return value of redirect is not used in any way.

Implications

If you redirect into a child route from afterModel, the beforeModel/model/afterModel hooks will still get called (or, instead of model, the provided transition context for that route will attempt to be resolved), on the grounds that afterModel is still one of the route-entry-validation hooks, and if you don't proceed beyond it, the entry into that route hasn't been validated.

If you redirect into a child route from redirect (by calling transitionTo), this route's beforeModel/model/afterModel hooks won't be called in that redirecting transition because entry into this route has already been validated.

So people who merely want to change the destination of a transition should use redirect. Those who want to say "try again" on this parent route should use afterModel. Note that these are only important considerations when the question is redirecting into a child route (vs the other child route you were already transitioning into).

Backwards compat considerations

I consider this change safe on the grounds that

  1. It's fixing buggy/undesirable behavior that people have been running into (3056 3407)
  2. No one who uses afterModel is also using redirect
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment