9

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!

7
  • 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. Commented May 5, 2016 at 19:24
  • 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). Commented May 5, 2016 at 19:45
  • Which resolve is fired twice ? Commented May 6, 2016 at 18:19
  • The one for state base and the one for state base.profile. You can see in the log (s.codepen.io/cprfnaporf/debug/RaqmQN). Commented May 6, 2016 at 18:26
  • 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... Commented May 6, 2016 at 18:41

2 Answers 2

4
+25

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Yeah, I understand all this, but the problem still remains. How can I avoid the additional resolves? Just leaving them there feels really ugly for me, but I don't want to update the url as that would be a bad UX as well in my opinion.
@Andrew I really understand your problem. But, I think that the main issue is with the app design and more specifically the states hierarchy.
No, I'm pretty sure that's all fine. See my last comment on BatteryAcid's answer! Thank you for your effort though!
4

@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

11 Comments

Well, that's the thing. It's not because of the .when statement. That's only there to illustrate the problem fast. The thing is, it happens on the initial page load even if it's not redirected, but I couldn't find a way to illustrate like that in codepen. So if you open /profile/x/details directly the problem still occurs. In the real application I'm not using this when statement.
Ok. What about handling the resolve more gracefully?
What do you propose? I really can't think of a way that would be easy to use app-wise. Basically I just want to show a real simple 404 page when any API call returns 404, without changing the url. Should I actually return some custom type of data and wrap every single API call? I'll be honest, that seems to me a huge overkill for such a small task. I'm not trying to nitpick here, I hope you understand. :)
@Andrew I pulled this code into a local Play Framework server, removed the when statement, and navigated to /profile/x/details/ and do not see details loaded twice. Unless I'm missing something, I think using the when to illustrate the problem is causing issues. Maybe we can tackle it another way?
Have you actually tried to load /profile/x/details initially? The problem only occurs on the initial page load, not when you navigate to it with ui-sref or anything like that.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.