Infinite Loop on ui-router's $stateChangeStart

2019-02-23 01:47发布

Ramping up on angular, and ui-router

And struggling with redirecting to a different state if a precondition is not met:

I tried using an interceptor: (How do I preform a redirect in an angular interceptor).

But someone mentioned that handling $stateChangeState would be more appropriate. But I am still running into an infinite loop:

    /**
     *  Check here for preconditions of state transitions
     */
    $rootScope.$on('$stateChangeStart', function(event, toState) {

        // which states in accounts to be selected
        var accountRequiredStates = ['user.list', 'user.new'];
        if(_.contains(accountRequiredStates, toState.name)){
            event.preventDefault();
            ApiAccount.customGET('get_current').then(function(resp){
                // if I have a selected account, go about your business
                if(resp.hasOwnProperty('id')){
                    $state.go(toState.name);
                } else { // prompt user to select account
                    $state.go('user.select_account');
                }
            })
        }
    });

Can anyone suggest a better pattern (one that works)

Thanks!


Note: Similar problem different approach here: How do I preform a redirect in an angular interceptor

1条回答
混吃等死
2楼-- · 2019-02-23 02:10

I don't think there's anything wrong with the general way you're trying to do this, though I'm not an expert. I do see a flaw in the implementation which looks like it could cause an infinite loop. Let's say the user tries to go to 'user.new' state. Your $stateChangeStart listener intercepts that, cancels it, does your customGET; then if the inner if condition is true (resp.hasOwnProperty('id')), you try to send the user to the same 'user.new' state. At which point, your $stateChangeStart listener intercepts it, cancels it, etc., over and over.

The way I avoid this problem in my code is to have a variable (in the service where I declare the listener) to help me bypass that check: var middleOfRedirecting = false; Inside your inner if block within the resp.hasOwnProperty('id') check, set middleOfRedirecting to true; add a condition at the start of your $stateChangeStart listener to only call event.preventDefault() and redirect if middleOfRedirecting is false. You also would need a $stateChangeSuccess listener to set middleOfRedirecting back to false, resetting it for the next state change. (I feel like there should be a better way than this, but it at least works.)

查看更多
登录 后发表回答