Skip to content
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

Redirect loop on state with errored resolve #1022

Closed
andyrooger opened this issue Apr 11, 2014 · 27 comments
Closed

Redirect loop on state with errored resolve #1022

andyrooger opened this issue Apr 11, 2014 · 27 comments
Assignees

Comments

@andyrooger
Copy link

In our code we are using the code in the faq for optional trailing slashes. We also have a number of states loading data using the resolve attribute.

I observe the following four cases when navigating to states that use resolve, both from other states, and when navigated to directly by URL:

Navigate from Data successfully resolved Data resolution failed
Another state Ends at expected state and url Stays on (or is returned to) original state and url
Another website Ends at expected state and url URL remains that of the failed state, but the actual state is '' or the abstract root state

If we then include the redirection for trailing slashes in the FAQ, and navigate to the same states but without a trailing / then all of these cases other than the bottom right remain the same.

When navigating directly to a state whose resolution fails, we get into a loop where the redirect adds a /, starting a transition to the state, the state then fails during its resolve and redirects back to the address without a /. This loop continues flipping the / back and forth until we receive the following two 'infinite digest' errors.

Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [["fn: $locationWatch; newVal: 7; oldVal: 6"],["fn: $locationWatch; newVal: 8; oldVal: 7"],["fn: $locationWatch; newVal: 9; oldVal: 8"],["fn: $locationWatch; newVal: 10; oldVal: 9"],["fn: $locationWatch; newVal: 11; oldVal: 10"]]
http://errors.angularjs.org/1.2.15/$rootScope/infdig?p0=10&p1=%5B%5B%22fn%3…2fn%3A%20%24locationWatch%3B%20newVal%3A%2011%3B%20oldVal%3A%2010%22%5D%5D
    at http://code.angularjs.org/1.2.15/angular.js:78:12
    at Scope.$digest (http://code.angularjs.org/1.2.15/angular.js:12070:19)
    at Scope.$apply (http://code.angularjs.org/1.2.15/angular.js:12279:24)
    at http://code.angularjs.org/1.2.15/angular.js:1382:15
    at Object.invoke (http://code.angularjs.org/1.2.15/angular.js:3805:17)
    at doBootstrap (http://code.angularjs.org/1.2.15/angular.js:1380:14)
    at bootstrap (http://code.angularjs.org/1.2.15/angular.js:1394:12)
    at angularInit (http://code.angularjs.org/1.2.15/angular.js:1307:5)
    at http://code.angularjs.org/1.2.15/angular.js:21163:5
    at HTMLDocument.trigger (http://code.angularjs.org/1.2.15/angular.js:2445:7) angular.js:9563
Uncaught Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [["fn: $locationWatch; newVal: 7; oldVal: 6"],["fn: $locationWatch; newVal: 8; oldVal: 7"],["fn: $locationWatch; newVal: 9; oldV...<omitted>...5D 

I am unsure of what the expected behavior here is, though I would assume a digest error is not it. I would probably expect the same behavior as I would see without the / redirect - stay on the original URL, or even the errored state's URL but not complete the transition.

Is there something I should do differently here to avoid this case, or is this a bug?

Plunker example here: http://plnkr.co/edit/28AQYE?p=preview

@fpetitit
Copy link

fpetitit commented May 7, 2014

Same issue on my project.
Have you found a solution for your application ?

@mfunkie
Copy link

mfunkie commented Jun 9, 2014

I got a similar issue when using ui-router on an angular app when another angular app existed on the page that did not use ui-router. My solution was to change my $urlRouterProvider.otherwise('/') to a function that just directly $state.go'ed to the intended default state. I know this is only tangentially related but it's definitely a hard problem to solve/lookup so hopefully I've helped someone here and we can figure out what's going on with the overall issue.

@andyrooger
Copy link
Author

My solution so far has been to drop support for optional trailing slashes. Our users should never need to type a URL manually so it's a niggle only for devs who keep getting urls wrong. I will be trying @mfunkie's suggestion though.

@mfunkie
Copy link

mfunkie commented Jun 10, 2014

My solution actually proved itself to not work downstream. My real issue was two separate Angular apps with a different idea of what $location.absUrl() should be. My hack was to put an event on $locationChangeStart in the app that didn't use routing. If there were more than 4 locationChangeStarts in a second, I prevented the default actions from occurring in the event handler and that solved my issue.

@Sljubura
Copy link

@mfunkie Thanks you so much for posting. I was looking for a solution for a whole day, and your use case is the same as mine.

@mfunkie
Copy link

mfunkie commented Jul 10, 2014

I wish I knew of a better way to fix it though. Right now I have a routing integration module I have to require on any angular app that coexists on a page with preexisting routing. It seems like an edge case but it's very real for legacy apps that are migrating to SPA over a long period of time.

@dmytro-shchurov
Copy link

It seems like we have faced to the same issue. $urlRouterProvider.otherwise forces to redirect to a complex /root/child/child state, which has resolve specified. Everything is fine in two cases: 1) When user url does not end with slash (like localhost/#) or 2) When exact state is specified in the url (like localhost/#/root/child/child).
In case url is typed as localhost/#/ we've got '10 $digest iterations reached'
Of course everything is fine in all cases when no resolve is used.
Resolved object is just a promise one, returned by $http or $resource.$promise; wrapping it with $q does not solve the problem

UPD.
As a result of investigation, the reason of such error was caused by a bug in code of resolving routine, which was raised only after a service was compiled run-time, and for some reason was not reported to a browser console. But everything else remains the same: '/#' and '#/state/' works (this means no infinite loop), '/#/' does not work.
PS I've found an example of more correct .otherwise() usage

$urlRouterProvider.otherwise(function ($injector) {
            var $state = $injector.get('$state');
            $state.go('your.state');
        });

which did not cause infinite loop. It's useful. But the compilation error is still not reported and it's sad. Test your resolvers before you use them with $state.

@rgroli
Copy link

rgroli commented Aug 25, 2014

@mfunkie Thank you! Your workaround with observing $locationChangeStart also worked in my project. For me it's still not clear what is actually causing this.

@KevinOl
Copy link

KevinOl commented Nov 20, 2014

Hi there,
I am new to AngularJS and have the same issue (at least it seems like). In a nutshell, if a user types in a url that is not defined in my states, she/he will be redirected to the home page. In my App.js, I have something like below,

$locationProvider.html5Mode(true);
$locationProvider.hashPrefix('!');
$stateProvider.state('home', {
url: '/',
templateUrl: [path_to_template],
controller: [a_controller],
resolve: [something]
});
$urlRouterProvider.otherwise('/');

If I remove $locationProvider it is fine but I'd like to keep the html5Mode. For now, I just wrap $urlRouterProvider in a try/catch. It works but I don't like that "work around".
Could the cause be in the resolve as mentioned by dmytro-shchurov? I will try some of the solutions above. Again, I am not sure what is going on...

Update:
This works too,
$urlRouterProvider.otherwise(function ($injector) {
var $state = $injector.get('$state');
$state.go('home');
});

@howieweiner
Copy link

Thanks @KevinOl Using the $injector worked for me. Seems to have changed/broken in latest release. Worked in 0.2.11, but not in 0.2.13

@raulgomis
Copy link

Any update on this issue??

@yousfiSaad
Copy link

Any update ..
i try to use it with angular-permission and it goes wrong

@xantorres
Copy link

It worked for me too @KevinOl thanks a lot

@benoror
Copy link

benoror commented Feb 27, 2015

Also fixed by using @dmytro-shchurov and @KevinOl solution:

$urlRouterProvider.otherwise(function($injector) {
  var $state = $injector.get('$state');
  $state.go('home');
});

Can anyone explain the cause behind it? Can we expect it to be fixed in a future release?

Cheers!

@lmk123
Copy link

lmk123 commented Apr 6, 2015

I use v0.2.13 and I didn't fix this issue by using @dmytro-shchurov and @KevinOl solution , BUT I found a solution at there. I hope it can help you ;)

@nateabele nateabele self-assigned this Apr 6, 2015
@raphaelluchini
Copy link

I'm getting a similar problem. I have an anchor www.website.com/#something and a route www.website.com/:slug/:param. When I hit the anchor and then I use url-sref or $state.go, I get Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting! after that the router call otherwise and redirect me to '/'

@morettimatheus
Copy link

@dmytro-shchurov solution also worked here. Thank you!

@kennethlynne
Copy link

A "throttle" solved it for me.

    var redirectInProgress = false;
    $urlRouterProvider.when(/^([\/])?$/, function ($state, $timeout) {
      if (!redirectInProgress) {
        redirectInProgress = true;
        $timeout(function () {
          redirectInProgress = false;
        }, 100);
        return $state.href(App.ui.states.spacesList);
      }
    });

@michaelcunningham19
Copy link

@dmytro-shchurov your solution fixed my same issue, using angular-ui-router 0.2.15 w/ angular 1.4.4

@eddiemonge
Copy link
Contributor

nihgwu added a commit to nihgwu/hexo-hey that referenced this issue Sep 14, 2015
@codedbypaul
Copy link

I just tried using the following but still get redirected back to the previous state.

$urlRouterProvider.otherwise(function($injector) {
  var $state = $injector.get('$state');
  $state.go('home');
});

@elvismdev
Copy link

Try placing a return before $state.go() ?

$urlRouterProvider.otherwise(function($injector) {
  var $state = $injector.get('$state');
  return $state.go('home');
});

@nfantone
Copy link

@eddiemonge This is still happening on 0.2.18 using Angular 1.5.2.

Above solution fixed it for me. Replacing .otherwise('some.state') with:

$urlRouterProvider.otherwise(function($injector) {
  var $state = $injector.get('$state');
  return $state.go('some.state');
});

prevents infinite looping.

Maybe re-open the issue?

@carlosdubus
Copy link

I also just experienced this with ionic. $urlRouterProvider.otherwise(function($injector)... Fixed the issue. Just spent 3 hours trying to figure out why the infinite loop.

@nfantone
Copy link

So... It's nearing two years and a half now...

@eddiemonge Is this still an ongoing issue?

@maleta
Copy link

maleta commented Apr 11, 2017

I can confirm that this bug still happens. I solved it with this:

$urlRouterProvider.otherwise(function($injector) {
  var $state = $injector.get('$state');
  return $state.go('some.state');
});

I am using Angular 1.6.4 and ui-router 0.4.2

@rameshkumarv
Copy link

I'm also faced the same issue, in my case I have $urlRouterProvider.otherwise("/dashboard") in route and event.preventDefault() in $stateChangeError block. I tried with code mentioned by boonep, that's not solved my case. Problem with my code was I missed /* @ngInject */ in myfile.js. Since I'm using typescript (Don't know exactly, may be build tool require this) I need to use

/* @ngInject */

Check the error parameter value to identify the exact cause.

$rootScope.$on("$stateChangeError", (event, toState, toParams, fromState, fromParams, error) => {
event.preventDefault();
$state.go("somestate");
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests