当 $state.go 调用 $stateChangeStart 时,Angular 1.4.1 UI 路由器 10 $digest() 迭代

问题描述:

我有一个需要授权的状态.我监听 $stateChangeStart 事件,如果 toState.data.protected 和用户没有被授权我调用 e.preventDefault()$state.go('login').

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').

当我在根 url 中打开应用程序时,我会自动重定向到受保护状态.这会导致 10 个 $digest 循环,当我在根 url 中打开应用程序时,我最终处于登录状态,并且我会自动重定向到受保护状态.

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.

未捕获的错误:[$rootScope:infdig] 已达到 10 个 $digest() 迭代.中止!

看到这个 plnkr:http://plnkr.co/edit/1voh7m?p=preview

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

我在不同的项目中成功使用了类似的代码,角度为 1.2.26,没有错误.

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

示例代码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. 拦截到 main.submain 状态的转换
  2. 开始转换到登录状态
  3. UI 路由器获取第一次转换被取消的信息
  4. UI 路由器运行 $urlRouter.update() 并开始转换到 main.submain
  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

简化的状态配置.

这是 UI.Router 的问题 – 在 Github 上查看此问题:https://github.com/angular-ui/ui-router/issues/600

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

基本上,如果您使用 .otherwise('/main')(也由@Grundy 指出),那么当路径无法访问时,url 将更改为 /main得到解决.在 $locationChangeSuccess 之后,我的监听器被调用,我使用 event.preventDefault() 拒绝重定向.这会导致位置变回未知路径,从而导致再次使用回退路径.这会导致无限循环.解决办法是这样的:

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');
});

您可以声明一个使用 $injector 调用的函数,并且您可以重定向到您的主状态(或 404),而无需来回更改位置.感谢 Github 上的人,我应该在发布这个问题之前在那里搜索.

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.

工作 plunk:http://plnkr.co/edit/eQXaIk