在$ stateChangeStart中使用$ state.go会导致无限循环

时间:2017-08-30 12:27:03

标签: angularjs angular-ui-router

我正在使用AngularJS ui-router。我正在尝试为未经身份验证的用户实施保护路由。我正在检查用户是否已登录$stateChangeStart。如果用户未登录,则重定向到登录状态。

但是当我在$state.go("login")处理程序中使用stateChangeStart时,处理程序代码进入无限循环并且出现控制台错误" RangeError:超出最大调用堆栈大小"

以下是我的代码:

$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams) {
    var allowedStates = ["signup","confirmaccount","resetPassword"];
    if(!$window.localStorage.getItem('userInfo') && !(allowedStates.includes($state.current.name)))
    {
        $state.go("login");
    }
}
);

以下是控制台错误的屏幕截图。

enter image description here

3 个答案:

答案 0 :(得分:2)

防止默认行为并在不使用$state.current.name的情况下检查允许状态,因为toState已经是$stateChangeStart的参数

更新

我认为你需要一个No State Change逻辑,而不是重定向到始终登录。

$rootScope.$on('$stateChangeStart',
  function(event, toState, toParams, fromState, fromParams) {
    var noChangeStates = ["login", "signup", "confirmaccount", "resetPassword"];
    var noStateChange = noChangeStates.indexOf(toState.name) > -1;

    if (noStateChange) {
      return;
    }

    //Check for Allowed or Not Allowed logic here then redirect to Login
    if (!$window.localStorage.getItem('userInfo')) {
        event.preventDefault();
        $state.go("login")
    }
  }
);

请注意,您还应添加"登录"无状态改变

答案 1 :(得分:0)

  

但是当我在stateChangeStart处理程序中使用$ state.go(" login")时,处理程序代码进入无限循环并且出现控制台错误" RangeError:超出最大调用堆栈大小&#34 ;

您似乎总是致电$state.go("login");

您可以查看toStatefromState,以避免拨打额外时间$state.go("login");

类似的东西:

if(!$window.localStorage.getItem('userInfo') 
   && !(allowedStates.includes($state.current.name))
   && fromState.name !== 'login'
){
    event.preventDefault();
    $state.go("login");
 }

答案 2 :(得分:0)

使用stateChange事件不是处理它的最佳方法。实际上,它做了什么:

  • 你改变了状态
  • 然后检查身份验证。

在更改状态之前检查会更好。为此,您可以使用ui-router' resolve

$stateProvider
  .state('login', { // Login page: do not need an authentication
    url: '/login',
    templateUrl: 'login.html',
    controller: 'loginCtrl',
  })
  .state('home', { // Authenticated users only (see resolve)
    url: '/home',
    templateUrl: 'home.html',
    controller: 'homeCtrl',
    resolve: { authenticate: authenticate }
  });

function authenticate($q, user, $state, $timeout) {
  if (user.isAuthenticated()) {
    // Resolve the promise successfully
    return $q.when()
  } else {
    // The next bit of code is asynchronously tricky.

    $timeout(function() {
      // This code runs after the authentication promise has been rejected.
      // Go to the log-in page
      $state.go('logInPage')
    })

    // Reject the authentication promise to prevent the state from loading
    return $q.reject()
  }
}

另见this answer