If I have a route to a state deep in the application, how do I ensure that the proper controller set up has been done although I'm going to enter the inner state directly?
For example,
- state A
- state a, representRoute: 'a'
- state B
- state b, representRoute: 'a/b'
- state C
- state c, representRoute: 'a/b/c'
- state D
- state d, representRoute: 'a/b/c/d
- state E
As you can see you can route directly to states 'a', 'b', 'c' or 'd', but what you can't see is that normally you would go between these states by selecting an item in a controller, which would then trigger a state transition to the deeper state. The problem then is that when you go directly to state 'd' none of your controllers' selections are set up.
So far I've used enterStateByRoute
in state 'a' to set the selection of the first controller and then had to use enterStateByRoute
in state 'b' to do the selection of the first and second controllers, etc. all the way to enterStateByRoute
in state 'd' to do the selection of each controller all the way along. This is quite wasteful, because I end up repeating the same code in each enterStateByRoute
.
What is the best way to set the controller selection to match the directly routed state?
I was able to improve the situation greatly once I realized that
enterStateByRoute
is called on all parent states in the chain when routing. This means that if state 'c' matches the route, state 'A' will be entered, followed by state 'B' and state 'C' before finally entering state 'c' last. What I didn't realize before was that each of these states is passed theSC.StateRouteHandlerContext
object as it is entered allowing you to either check the context inenterState
or implemententerStateByRoute
in any of the states.My solution then was to add
enterStateByRoute
to state 'A' to set the first controller, addenterStateByRoute
to state 'B' to set the second controller, etc. For example, in this way, any state past state 'A' is guaranteed to have the first controller selection set and I don't have any duplicated code down the chain.For example,
The only problem I encountered was that because I had bound all my controllers together, the selection change doesn't propagate immediately and so I would select an object on a controller in the first state, enter the next state and find that the bound controllers' content would not yet have updated.
So I could have waited for bindings to flush by returning an
SC.Async
object inenterStateByRoute
and usedthis.invokeLast(function () { this.resumeGotoState(); })
to go to the next state at the end of the run loop, but instead I took a declarative approach and simply set/unset each controller's content as I enter/exit the appropriate state.