-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Not possible to add state.resolve from $stateChangeStart event #1165
Comments
Seems like it could be handy. |
Same problem here. I can't add a custom $stateProvider
.state("home", {
url: "/",
resolve: {} // add {} default
}) |
Interestingly, resolve is one of the only fields on state that can't be decorated via the standard API. However, you can decorate it another, uglier way.
|
👍 very useful. I sometimes load additional resources (css/js/images..) before showing a route, making sure it's fully loaded. I'm switching now to |
As @NecoleYu wrote (thanks!), initializing the state definitions with $stateProvider
.state 'home',
url: "/"
resolve: {}
...
$rootScope.$on '$stateChangeStart', (e, toState, toParams, fromState, fromParams) ->
toState.resolve.x = ->
$timeout ->
alert "done"
, 3000 but would be nicer not to need this. |
@elado Agree |
@elado Very useful follow up comment |
Oh that possibillity would be wonderful! |
Need it so much. Very handy. +1 |
I'd love to see this as well. I wasn't able to make @christopherthielen's workaround work, though I was scratching my head as to why. Perhaps it depends on the nesting. Stepping through it, it appears the decoration has to happen before the state building is queued, for whatever reason. No hooks to work with there so for now I wrapped |
+1. That would be really helpful! |
also struggeld with this problem because some states had a defined resolve object and some did not.
Now i use the decorator suggested by @christopherthielen ! Thanks :) But it should be possible to extend the resolve method without this "hack"! 👍 |
Thanks all for the comments, this is gold! :) 👍 |
We've added this capability to the 1.0 code:
Alternatively, if you just want to delay the transition, you can return a promise from the hook:
|
@christopherthielen I tried to use this method for ACL, but I'm running into a problem prevent route change if route/state rejected. If I use onStart, I can't access
I haven't tried using addResolves yet. I previously had this working using ngRoute with resolves. The transition handler seems to be more appropriate for this case. |
Tried using addResolves, but that doesn't seem to be doing it either:
I get no console logs. |
You should inject
Odd, that should stop the state change... edit: yes, it should stop the state change. Check the console trace: http://plnkr.co/edit/6hWLzBGawc8VcjKvNGHi?p=preview |
Yep, that works. Though, now I'm wondering why to/from are functions.
After some testing I found that if I use ui-sref then the route properly never changes to the rejected route, but when I use href or just type the rejected route into the location bar, the state change is rejected (views remain on previous states), but the URI in the location bar remains the rejected route. I would have expected the previously valid route to overwrite the rejected URI in the location bar. Is there another step I need to do to prevent directly navigating to invalid routes (those where I return a reject from onStart)? |
Also, $stateChangeError doesn't fire when a rejection is returned from onStart |
The See how this hook works: https://github.com/ui-router/sample-app/blob/master/app/routerhooks/redirectTo.js
I think you are describing #2455 which is fixed in master
Did you re-enable the deprecated state events by adding See the release notes for what I'm referring to: https://github.com/angular-ui/ui-router/releases/tag/1.0.0alpha0
|
Unless I misunderstand your answer, I didn't mean the matching criteria ({ to: '', from: '' }), but rather the to() method on injectable
I'm not sure how to access that fix, unless it gets merged into 1.0.0alpha0. In any case, I made the modification specified in 25e0c04 locally, but doesn't fix either use case of HREF on an anchor or direct URL manipulation in the address bar. In both cases, the rejected URL remains in the address bar. I noticed another side effect: after I click on an HREF link to a rejected route, the address bar changes to the new route and the current state remains, but then if I click on a UI-SREF link to go to the state I'm currently on (though the address bar says otherwise) the address bar doesn't change back to the current valid route, because it thinks I'm already there, which also raises an onError. If I refresh while the rejected route is in the address bar, I'll get no view at all (I'd expect the "otherwise" route).
Nope. You're right. I read that right after I posted. It seems the alternative is using onError along with $transition$.error(), but $transition$.error() is just giving me undefined and I need to be able to access the passed rejection object. |
Oh, I see... it's just an accessor method so we can change where the value comes from in the future without disrupting the API.
It's merged into 1.0 because
Ah yes, you're right. Would you mind opening a new ticket for that issue? Here's a plunk http://plnkr.co/edit/9uVnia9Vikx6Dcxgaz1P?p=preview
I see you're implementing a global ACL. One of the primary drivers for the design of the transition hooks was adding custom global behaviors like this. I'd like the hooks to be sensible for you and your use case, and if they are not, I want to understand where the gaps are. Where would you like to check for your ACL transition rejection? In that same plunk I added a global error hook: http://plnkr.co/edit/9uVnia9Vikx6Dcxgaz1P?p=preview
|
Forgive me, I'm fairly new to git, so what exactly should I tell bower to download, because I tried
.
It looks like your plunk rejects with In my current use case I have two separate hooks corresponding to two different contexts of ACL, but they both run and both could fail, and either failure requires the same redirect, and if both fail at the same time I don't want two redirects to occur. Previously, when using $stateChangeError, it would be called only once and I could check which one of the failures was raised, and redirect once. So, will onError be called once with the error that caused it, or will it be called once for every onStart/onEnter that rejected? If it is called more than once then I'd have to somehow make sure there isn't a double redirect. |
1.0.0alpha0 is a released build. We don't publish daily snapshots, so you'd have to build it yourself
Then use
Click the link labelled "Click this Link" to see the onEnter rejection happen.
The hooks are run as a chain, in a specific order (onBefore -> onStart -> onExit -> onRetain -> onEnter -> onFinish -> onSuccess/onError). A transition can only be rejected by one hook. |
I do use npm for tools and libraries related to building my app, but I use bower for libraries that will be actually included in the app, because bower offers the main property, which allows me to
Yeah, I must have been looking at the ignore error for the state that was already applied. I do see that
So, I take that to mean that if one onEnter rejects a route, any other onEnter's (for the same route/state change) won't even run. That's fine. |
I've moved to ES6 modules and a bundler (webpack, etc), but now we're quite off topic ;)
The same way: as
Correct |
Closing since adding resolves on the fly is possible in 1.0 |
Can you please post an example using |
See: https://ui-router.github.io/ng1/docs/latest/classes/transition.transition-1.html#addresolvable transitionService.onBefore({ to: state => state.data.dostuff }, trans => {
trans.addResolvable({ token: 'myResolve', deps: ['MyService'], resolveFn: MyService => MyService.getStuff() });
}); |
@christopherthielen thank you! That example helps! I think I was frustrated and had to bounce around to see the constructor implementation and have a tough time reading the font face or something. Still haven't quite figured out how to navigate everything. Probably my impatience |
@stephengardner in the past, you HAD to use the
In I'll add an example to the docs. ui-router/core@6d41c31 |
Adding my route authentication as an example, Thanks again for the clarification @christopherthielen /**
* Authentication Resolvable - if I add "authenticate" to a route params, this will make sure the user is logged in
* before proceeding.
*/
$transitions.onStart({}, (trans) => { // on any route, do the following...
let next = trans.to(); // get the state and its params
if (next.authenticate) {
trans.addResolvable({
token : 'authResolve', // the token can be anything, here, we never actually use it in this specific case
deps : ['$state', 'Auth', '$q'], // inject what I need
resolveFn: ($state, Auth, $q) => {
return new $q((resolve, reject) => { // make sure this is a promise, in order to delay the route
let onUserLoggedIn = () => {
console.log('[Auth Service] the necessary *authenticate* state PASSED the resolvable, continue on!');
return resolve();
};
let onUserLoggedOut = () => {
console.log('[Auth Service] the necessary *authenticate* state FAILED the resolvable, going to login page!');
$state.go('login');
return reject();
};
// this can be substituted for any promise, observable, or async operation, here I'm using an observable
Auth.isLoggedInAsync$().subscribe((isLoggedIn) => {
if(!isLoggedIn) return onUserLoggedOut();
return onUserLoggedIn();
})
})
}
}); }
}); |
@christopherthielen Thank you for the example. I use same code like this:
It works fine but when I try to add 'myResolve' as a dependency to my page controller, it is undefined (and I am sure I resolve the promise to a value). |
@arashsoft is the "page controller" a routed controller? In other words, is it found inside a state definition? |
@christopherthielen Yes it is the state controller. I will create a plunker and send it here. |
Overview:
Sometimes it's desirable to add state resolves on the fly, instead of needing to add them to all states beforehand. For example, a resolve that verifies a user is authenticated or fetches the user from an API.
It's possible to do this with
$routeChangeSuccess
using the following code:However the same is not possible with
$stateChangeSuccess
. This is because the event is broadcast withto.self
, see this line. This means if you add a resolve in the $stateChangeSuccess event, you are actually adding onto.self.resolve
which is never considered for resolve._Related:_
#1153
The text was updated successfully, but these errors were encountered: