-
Notifications
You must be signed in to change notification settings - Fork 3k
$state injection into resolve function gives old state #238
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
It's a little tricky... $state is a service, so there really is only one $state. We also can't really update $state.current before the resolve process starts, because (1) it's asynchronous, so the state hasn't changed yet, and (2) it could fail. I'm thinking a nice way to solve this would be to have a special injectable like '$transition' which would be the transition object for the current transition, with properties like 'to', 'from', 'toParams', 'fromParams', ... |
Yeah, 👍. The |
Yeah, i think the 3rd parameter to transitionTo becomes the transition object |
This seems like a design flaw that does make rather common use cases virtually impossible. If my route includes a I understand the timing issues involved, but this strikes me as a fairly huge hole in the system. |
@oncomeme -- can't you access the parameter directly in your resolve, instead of seeking it out in the $state service? Or am I misunderstanding? |
@oncomeme - as @stu-salsbury mentioned, you can inject |
It works. It's also really awkward and makes it impossible to define a truly standalone service as it has to be baby fed by everything that wants to use it. |
I believe the phrase is "patches are welcome". |
URL parameters of a state are parameters of a state. As such I would consider it bad design (essentially a layering violation) for a service to access these directly. A state-level 'resolve' that passes correct parameters to the correct service is the way to go. |
Be careful about naming conventions as $transition is used inside of ui-bootstrap and may get picked up by animation code in the core. |
@ProLoser I've been thinking there should be a naming convention for "local" magical values that are injectable, that makes them easily distinguishable from global services. Maybe |
@ksperling I've been thinking, what if, instead of a separate service, we just overwrote |
@nateabele that makes sense to me. The $transition service idea felt like it could get more complicated for users. Also keeps the transition object "namespaced" on $state, so we'll avoid the naming convention issues @ProLoser mentioned (which obviously is your goal). I like it. |
@nateabele Not sure that really solves it... I think the code that runs during the processing of a transition always has to see "new" values relating to that transition, where as everything else shouldn't see that data until the transition succeeds. For example if while the resolve is running the user does something else in the UI, that code needs to see the previous values. Also, if a second transition gets started which supersedes one that is currently running, the values for the second one should be separate from what the previous one is looking at, otherwise it will be pretty easy to get unpredictable stuff happening. I think having a special injectable like |
@ksperling hmmm, well sounds like $state.transition is too hard to implement (or just not feasible). I'm not sure how I feel about the |
Why not let it see everything? Here's a proposed object structure: $state.transition = angular.extend($promise, {
to: targetState,
from: currentState,
params: {
to: { ...all params for target state... },
from: { ...all params for current state...}
}
}); The Am I missing anything here? |
@nateabele Imagine you do something like
Any resolve functions, callbacks etc that happen as part of settings up that first transition need to see id==1. Anything that happens as part of the second transition needs to see id == 2. Additionally, any global service that happens to look at e.g. $stateParams before either of these two transitions completes shouldn't see either id==1 or id==2, but should see whatever was in $stateParams before -- essentially a transition that's in progress is analogous to an uncommitted database transaction; nobody else should see those values (yet). So what I'm saying is that a transition has this private information (which is currently just $stateParams, but I'd like to have a transition object with 'state', 'params', 'fromState', 'fromParams'), which only becomes (or gets copied into) globally accessible $state once the transition succeeds. To make this private information available, we're using the 'locals' parameter of $injector.invoke. I was arguing that using an identifier like I agree that we can also expose the latest active transition object as $state.transition, but that doesn't replace the need for a special injectable like |
@ksperling Okay, so essentially the transition information needs to be scoped in the same way as Also, as far as names go, I think a name like |
@nateabele yes on the scoping. I think $stateTransition is OK, I just think it might be good to avoid the confusion of global vs scoped behaviour that we currently have with $stateParams. In that sense I consider I think we could even go so far as removing $stateParams as a global service, and allowing it to be access as $state.params in the global context (only completed transitions) and as If we go with $stateParams and $stateTransition it will appear more obvious at first, but then we'll get the issues like we've seen where people inject it into a service and it doesn't behave how they expect. |
@ksperling I actually agree now. It is a new type of injectable that |
@nateabele I had $stateTransition property to state obj, now we can get an access to 'toState' property in the resolve function.. |
How about:
|
Related to #578 |
+1 I've had to work around this in my current app by observing This is an important feature in order for a parent state to intercept a route and set a default parameter if missing. |
This has been superseded by #1257. Please follow that issue for updates. Thanks! |
When passing in $state into a resolve function, it seems to provide the old state, not the new state that we're resolving for.
resolve: {
model: ["$state", function($state){
//$state.current gives info for old state here
}]
}
This is a problem as we can't access custom state data in the resolve function.
The text was updated successfully, but these errors were encountered: