Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 1.4.1 UI Router 10 $digest() iterations when $state.go called on $stateChangeStart

I have a state that requires authorization. I listen to the $stateChangeStart event and if the toState.data.protectedand the user is not authorized I call e.preventDefault() and $state.go('login').

When I open the app in root url I'm automatically redirected to protected state. This causes 10 $digest loops and I end up in the login state when I open the app in the root url and I'm automatically redirected to a protected state.

Uncaught Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!

See this plnkr: http://plnkr.co/edit/1voh7m?p=preview

I successfully use similar code in different project with angular 1.2.26 with no errors.

Example code angular 1.4.1, ui.router 0.2.15:

//config block
$urlRouterProvider.otherwise('/main');   
$stateProvider
 .state('main', {
   url: '/main',
     templateUrl: 'main.html',
     controller: 'MainController as main',
     data: {'protected': true}
 }) 
 .state('login', {
     url: '/login',
     templateUrl: 'login.html',
     controller: 'LoginController as login'
 });

// in a run block
$rootScope.$on("$stateChangeStart", function (event, toState) {
    if (!event.defaultPrevented && toState.data &&
            toState.data.protected) {
        // the user is not authorized, do not switch to state
        event.preventDefault();
        // go to login page
        $state.go('login');
    }
});

Do you know what causes the loop?

I wonder if the things might be happening like this:

  1. Intercept the transition to main.submain state
  2. Start transition to login state
  3. UI router gets the information that the first transiotion got cancelled
  4. UI router runs $urlRouter.update() and starts transition to main.submain

EDIT: Simplified state configuration.

like image 284
kvetis Avatar asked Dec 05 '22 21:12

kvetis


1 Answers

This is an issue of the UI.Router – see this issue on Github: https://github.com/angular-ui/ui-router/issues/600

Basically, if you use .otherwise('/main') (also pointed out by @Grundy) then the url is changed to /main when the path cannot be resolved. After $locationChangeSuccess my listener is called and I reject the redirection using event.preventDefault(). This causes the location to change back to the unknown path thus causing the fallback path to be used again. This causes the infinite loop. The solution is this:

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

You can state a function which gets called with $injector and you can redirect to your main state (or 404) without back-and-forth location changes. Thx to the guys on Github, I should have searched there before posting this question.

Working plunk: http://plnkr.co/edit/eQXaIk

like image 146
kvetis Avatar answered Feb 16 '23 03:02

kvetis