Lazy transitions when providing a promise as an argument to `transitionTo`

Hi Ember folks,

I have an idea for a possible change to the behavior of the router “loading” and “error” substates.

The routing guide describes the handling of transition promises:

If the model hook … returns a promise (or if a promise was provided as an argument to transitionTo), the transition will pause until that promise fulfills or rejects. (link)

It also describes the difference between “eager” and “lazy” transitions:

If you provide [a loading substate], you are essentially telling Ember that you want this async transition to be “eager”; [otherwise] the router will “lazily” remain on the pre-transition route while all of the destination routes’ promises resolve. (link)

That is, the router treats all promises the same, whether they were returned from a model hook, or passed in to transitionTo, and loading/error substates are always resolved based on the target route of the transition.

This works really well when returning a promise from a model hook because the app can enter a very specific loading/error substate.

It doesn’t always seem to work well when passing a promise in to transitionTo, though. When the target route and its parent “resource” route share the same model object, it’s not possible to enter the target route’s “sibling” loading state, even if the source route is also a child of that “resource” route. You must settle for the parent “resource” route’s sibling loading state.

So, what I’ve noticed about my usage is that when I provide a promise as an argument to transitionTo(), I actually want the router to treat that as a “lazy” transition. That is, I want to stay on the source route until the promise resolves (or rejects). Staying on the source route would allow the router to resolve the loading substate (and maybe the error substate?) relative to the source route (rather than the destination route).

What do you think? Would that work better for you and your app? Worse?

1 Like

@real_ate It seems like you ran into something similar. Do you have any thoughts on this?

@nonsensery my use case was more along the lines of re-using the Error/Loading states for cases when an action handler returned a promise i.e. when an action handler needed to hit a 3rd party HTTP api

Yeah, I guess I was thinking along the same lines for transitionTo(). My use case was to hit a 3rd-party API in an action handler, and pass that request/promise in as the model argument for transitionTo(). This works (in that the router enters a loading state while the request is inflight), but I think it could be more useful.

I like your wording of “re-using the error/loading states”. It seems like the error/loading states were designed with only the model hooks in mind. Their behavior when using promises with transitionTo() seems to be an afterthought. For example, the ember guide page doesn’t even mention transitionTo().

Maybe it would help to think of the current error/loading state functionality as something that works only with the model hooks. Any other use (whether it’s returning a promise from an action handler, or providing one as a transitionTo() argument) as a new way of [re-]using these states.

Well that’s an interesting way to think about it, but not too dissimilar to my first attempt at dealing with this issue.

We ended up creating essentially dummy sub-routes that the action handler did nothing but transition to. In those sub routes we had beforeModel() hooks that would hit the third party service. Those beforeModel() hooks could then roll back the transition if it wasn’t a successful request.

If your eyes haven’t started bleeding reading that description of what we did just consider the fact that this is greatly simplified, the actual implementation was way worse than it sounds above and I still think it sounds pretty bad.

I agree also that the loading states don’t seem to be designed for use with actions but I can’t find much documentation or many articles that suggest how you should deal with long running action handlers. Considering the “Ember Way” maybe we’re just doing it wrong? It would be great to get some architectural influence on this discussion :smile: