延迟控制器执行,直到分配了 rootScope 属性的值



情况是,我在(运行("routeChangeSuccess">事件。该事件根据 REST 请求响应状态代码更改 $rootScope.已验证的值。

但是,当触发事件并且我尝试将其中一个控制器中的 $rootScope.authenticated 值打印到控制台时,它说它是"未定义"的值。

角度运行:

pos.run(function($rootScope,$log,apiService){
// register event
$rootScope.$on('$routeChangeSuccess', function () {
    // call api function
    apiService.is_authenticated().then(
        function(response){
            if(response.status == "AUTHENTICATED"){
                $rootScope.authenticated = true;
            }else if(response.status == "NOT_AUTHENTICATED"){
                $rootScope.authenticated = false;
            }
        });       
    })
});

控制器:

// controller
pos.controller('TestController', function($rootScope,$scope,$http) {
    console.log($rootScope.authenticated);
});

它应该打印"真"或"假"。我知道它在执行控件后分配值,但是如何延迟执行控制器直到分配该值?

事实是,如果您使用$promise模式,则永远无法保证执行顺序,因为它是异步的,或者具有足够"安全"的延迟。

您可能想在其他地方进行更改,一种方法是使其同步:

if (apiService.is_authenticated()){
   $rootScope.authenticated = true;
}

另一种是$broadcast或$emit,也许在"运行"中再次收听

$rootScope.$on("LOGIN_SUCCESSFUL", function () {
   $rootScope.authenticated = true;
});

您可以合并$watch

或使用 http 拦截器

更多承诺和/或链接承诺

很多方法,但这取决于你!

最近研究了相同的解决方案,并在SO上阅读了很多答案。实际上有很多东西要找,但没有一个被接受的答案实际上对我有用。我找到了一个适用于最新ui路由器的答案,但不接受:

它调用 stateChangeStart 事件上的 preventDefault,然后你可以履行你的承诺。 如果成功,则设置一个绕过标志,并再次转换到相同的状态,但由于绕过标志而跳过承诺/解析部分:

$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
    if($rootScope.stateChangeBypass || toState.name === 'login') {
        $rootScope.stateChangeBypass = false;
        return;
    }
    event.preventDefault();
    Auth.getCurrentUser().then(function(user) {
        if (user) {
            $rootScope.stateChangeBypass = true;
            $state.go(toState, toParams);
        } else {
            $state.go('login');
        }
    });
});

取自: https://stackoverflow.com/a/28827077/2019281

我目前正在研究的另一个选项是使用根状态定义的解析对象。Resolve非常适合这一点,因为它将阻止控制器初始化,直到承诺被解析或拒绝。您可以在拒绝时抛出错误,您可以在应用程序的运行方法中捕获该错误:

状态定义:

$stateProvider.state('admin', {
    'url': '/admin',
    'controller': 'adminController',
    'templateUrl': 'admin.html'
    'resolve': {
        'auth': [
            '$q', 'Auth',
            function ($q, Auth) {
                return Auth.getCurrentUser().then(
                    function resolved (user) {
                        return (user) ? user : $q.reject('authRejected');
                    },
                    function rejected (user) {
                        return $q.reject('authRejected');
                    }
                });
            }
        ]
    }
});

应用的运行方法:

$rootScope.$on('$stateChangeError', function (e, toState, toParams, fromState, fromParams, error) {
    if (error === 'authRejected') {
            $state.go('login');
    }
});
缺点是您需要将根状态添加到

要保护的状态,或者将该解析添加到要保护的每个状态。此外,您始终需要在状态更改上使用reload: true,以便解析将在每次状态更改时重新加载。

灵感来源:https://stackoverflow.com/a/24585005/2019281

最新更新