延迟控制器执行,直到分配rootScope attirbute的值

时间:2016-02-02 14:09:03

标签: javascript angularjs

情况是,我在(运行)处有“routeChangeSuccess”事件。该事件根据REST请求响应状态代码更改 $ rootScope.authenticated 的值。

但是当事件被触发并且我尝试在我的一个控制器中向控制台打印 $ 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);
});

它应该打印“true”或“false”。我知道它在控制执行后分配值,但是如何延迟执行控制器直到分配该值?

2 个答案:

答案 0 :(得分:2)

事实是,如果你使用$ promise模式,你永远不能保证执行顺序,因为它是异步的,或者具有足够“安全”的延迟。

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

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

另一个是拥有$broadcast or $emit并在“再次”运行中听取它

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

您可以合并到$watch

或使用http Interceptor

more promises and/or chaining promises

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

答案 1 :(得分:1)

最近在同一个解决方案上工作并在此处阅读了大量答案。实际上有很多东西要找,但是没有一个可接受的答案对我有用。我找到了一个适用于最新ui-router的答案,但它并没有被接受:

它在stateChangeStart事件上调用preventDefault,然后你可以满足你的承诺。如果成功则设置旁路标志并再次转换到相同的状态,但由于旁路标志而跳过promise / resolve部分:

$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对象。 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');
                    }
                });
            }
        ]
    }
});

App的运行方法:

$rootScope.$on('$stateChangeError', function (e, toState, toParams, fromState, fromParams, error) {
    if (error === 'authRejected') {
            $state.go('login');
    }
});

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

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