9
votes

This has been driving me crazy for the last couple of hours and I can't find a solution still...

Basically I'm changing the state to 404 when a resolve returns an http 404 status code. I'm changing the state in $stateChangeError event. It all works fine, except after the state is changed to 404 it starts another state change back to the original one thus resolving twice. The state itself remains on 404, so after all, it works, but it still makes additional $http requests that are not needed. However, it only works like this if I use $state.go('404', null, { location: false }) OR if the 404 state doesn't have an URL defined at all.

If I have an url defined for the 404 state (/404), then everything works just fine.

Here are 2 pens, demonstrating the issue:

The failing one: http://codepen.io/cprfnaporf/pen/RaqmQN (debug mode, check console: http://s.codepen.io/cprfnaporf/debug/RaqmQN/)

The working one: http://codepen.io/cprfnaporf/pen/MyzdVQ (debug mode, check console: http://s.codepen.io/cprfnaporf/debug/MyzdVQ/)

Any idea how to fix this issue? I'm out of ideas really.

Thanks!

2
Please specify your exact desired functionality. Do you want to change to 404 state without showing a new view? Just not sure what your end goal is. - BatteryAcid
I want to change the state to 404 without changing the url. That works, but as you can see in the console the resolves run twice in that case (for some reason it tries to load the state with the resolves again). - Andrew
Which resolve is fired twice ? - Zakaria
The one for state base and the one for state base.profile. You can see in the log (s.codepen.io/cprfnaporf/debug/RaqmQN). - Andrew
I did a comparaison of logs and haven't seen anything difference. I just tried to debug but can't see which state is fired back when the 404 state is loaded... - Zakaria

2 Answers

4
votes

For me, you've already found the solution. Indeed, as stated in your code :

$urlRouterProvider.when('/', '/profile/x/details');

The default url is /profile/x/details. When the ui-router sees that url, it will try to load the states hierarchy : base, base.profile et base.profile.details. As you said, the last won't be loaded since you catch a 404 error and redirect the request elsewhere.

The problem is that you are still located at /profile/x/details. So in the stateChangeError, when you did the $state.go('404', null, { location: false });, ui-router will check for the url.

Since it isn't set in the 404, he will take the one he has : /profile/x/details. And this is why he resolve the same states hierarchy : base, base.profile et base.profile.details.

4
votes

@Andrew I guess I'm not sure exactly what your goals are but it seems like you're fighting the way ui-router works.

@Zakaria does a good job summarizing the issues.

Maybe take a step back and see if it really makes sense to keep a user on a dead page or partially dead page. If you are trying to handle a failed resolve, then maybe catch that 404 (or failed request) and return a default resolve instead of moving to a new error state. By keeping your when statement at $urlRouterProvider.when('/', '/profile/x/details'); you are only going to run into problems the way it's currently designed