AngularJS ui router $stateChangeStart with promise无限循环

AngularJS ui router $stateChangeStart with promise inifinite loop

本文关键字:with promise 无限循环 stateChangeStart ui router AngularJS      更新时间:2023-09-26

我试图在我的angular应用程序中建立某种身份验证,并希望在用户未登录时重定向到外部URL(基于$http.get)。

当event.preventDefault()是$stateChangeStart的第一行时,我最终陷入了一个无限循环。

我在stackoverflow上看到过多个问题的答案,比如"将event.preventDefault()放在状态之前。进入else"。但是随后控制器被触发,并且在promise返回之前页面已经显示。

即使我将event.preventDefault()放在else中,也会发生奇怪的事情:

进入根URL,它会自动在URL后面添加/#/,并且会多次触发$stateChangeStart。

app.js运行部分:

.run(['$rootScope', '$window', '$state', 'authentication', function ($rootScope, $window, $state, authentication) {
    $rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
        event.preventDefault();
        authentication.identity()
        .then(function (identity) {
             if (!authentication.isAuthenticated()) {
                 $window.location.href = 'external URL';
                 return;
            } else {
                 $state.go(toState, toParams);
            }
        });
    });
}]);

authentication.factory.js identity() function:

function getIdentity() {
    if (_identity) {
        _authenticated = true;
        deferred.resolve(_identity);
        return deferred.promise;
    }
    return $http.get('URL')
    .then(function (identity) { 
        _authenticated = true;
        _identity = identity;
        return _identity;
    }, function () {
        _authenticated = false;
    });
}

EDIT:添加状态:

$stateProvider
    .state('site', {
        url: '',
        abstract: true,
        views: {
            'feeds': {
                templateUrl: 'partials/feeds.html',
                controller: 'userFeedsController as userFeedsCtrl'
            }
        },
        resolve: ['$window', 'authentication', function ($window, authentication) {
            authentication.identity()
            .then(function (identity) {
                if (!authentication.isAuthenticated()) {
                    $window.location.href = 'external URL';
                }
            })
        }]
    })
    .state('site.start', {
        url: '/',
        views: {
            'container@': {
                templateUrl: 'partials/start.html'
            }
        }
    })
    .state('site.itemList', {
        url: '/feed/{feedId}',
        views: {
            'container@': {
                templateUrl: 'partials/item-list.html',
                controller: 'itemListController as itemListCtrl'
            }
        }
    })
    .state('site.itemDetails', {
        url: '/items/{itemId}',
        views: {
            'container@': {
                templateUrl: 'partials/item-details.html',
                controller: 'itemsController as itemsCtrl'
            }
        }
    })
}])

如果你需要更多的信息,或者更多的app.js代码让我知道!

$stateChangeStart不会等待您的承诺被解决后才退出。让状态等待承诺的唯一方法是在状态的选项中使用resolve

.config(function($stateProvider) {
  $stateProvider.state('home', {
    url: '/',
    resolve: {
      auth: function($window, authentication) {
        return authentication.identity().then(function (identity) {
           if (!authentication.isAuthenticated()) {
             $window.location.href = 'external URL';
           }
        });
      }
    }
  });
});

通过从函数返回一个promise, ui-router在promise被解析之前不会初始化状态。

如果你有其他或子状态需要等待这个,你需要注入auth

来自维基:

如果你想在实例化子节点之前等待承诺被解析,那么必须将解析键注入子节点状态。