【问题标题】:Resolve not called the second time解决第二次未调用
【发布时间】:2015-12-06 18:34:37
【问题描述】:

我有一些这样定义的路线:

$stateProvider
            .state('app', {
                url: '/',
                abstract: true,
                views: {
                    'menuContent': {
                        templateUrl: 'templates/home.html'
                    }
                }
            })
            .state('app.restricted', {
                url: '/restricted',
                views: {
                    'content': {
                        templateUrl: 'templates/restricted/restricted-dashboard.html',
                        controller: 'RestrictedController as vmRestricted'
                    }
                },
                resolve: {
                    isGranted: 'isGranted'
                }
            })
            .state('app.restricted.pending', {
                url: '/pending',
                views: {
                    'tabsView': {
                        templateUrl: 'templates/restricted/restricted-manage-pending.html',
                        controller: 'RestrictedPendingController as vm'
                    }
                },
                resolve: {
                    isGranted: 'isGranted'
                }
            })
            .state('app.restricted.devices', {
                url: '/devices',
                views: {
                    'tabsView': {
                        templateUrl: 'templates/trusted/restricted-manage-devices.html',
                        controller: 'RestrictedDevicesController as vm'
                    }
                },
                resolve: {
                    isGranted: 'isGranted'
                }
            })
            .state('app.grant', {
                url: '/grant-access',
                views: {
                    'content': {
                        templateUrl: 'templates/grant-access.html',
                        controller: 'GrantAccessController as vm'
                    }
                }
            })
        ;

在这些路线中,我有一个限制区域和一个授予访问权限页面以授予对限制区域的访问权限。 当isGranted 解析提供程序被拒绝时,我重定向到app.grant 路由。

这是执行此操作的代码:

$rootScope.$on(AngularEvents.STATE_CHANGE_ERROR, _onStateChangeError);

function _onStateChangeError(event, toState, toParams, fromState, fromParams, error){

            switch (error) {

                case 'accessRejected':
                    $state.go('app.grant');
                    break;

            }

        }

这是我的isGranted 提供者的代码:

(function() {

    'use strict';

    angular.module('app')
        .provider('isGranted', isGrantedProvider);

    isGrantedProvider.$inject = [];

    function isGrantedProvider() {

        this.$get = isGranted;

        isGranted.$inject = ['$q', '$log', 'grantService'];

        function isGranted($q, $log, grantService){
            $log.log('isGrantedProvider');

            if (grantService.isGranted()) {
                return $q.when(true);
            } else {
                return $q.reject('accessRejected');
            }
        }

    }

})();

(grantService.isGranted() 只是返回一个布尔值)

当我第一次使用$state.go('app.restricted')app.restricted 路由时,提供程序被执行。 该路由被拒绝,因为访问未被授予,我们被重定向到app.grant 路由。

在此页面中,用户可以登录并访问受限区域。用户登录后,我们将他重定向到 app.restricted.pending 路由,但未调用解析,路由被拒绝,我们再次重定向到 app.grant 路由,而访问被授予。

为什么没有调用 resolve? 有办法强制吗?

编辑

经过一些测试,我有了新的信息。

我看到只有当它是服务时才第二次调用resolve:

这个resolve总是在我们进入状态时执行:

state('app.restricted', {
                url: '/restricted',
                views: {
                    'content': {
                        templateUrl: 'templates/restricted/restricted-dashboard.html',
                        controller: 'RestrictedController as vmRestricted'
                    }
                },
                resolve: {
                    isGranted: ['$log', function($log) {
                        $log.log('RESOLVE');
                    }]
                }
            })

但是即使我再次进入状态,这个解析也只会执行一次:

state('app.restricted', {
                    url: '/restricted',
                    views: {
                        'content': {
                            templateUrl: 'templates/restricted/restricted-dashboard.html',
                            controller: 'RestrictedController as vmRestricted'
                        }
                    },
                    resolve: {
                        isGranted: 'isGranted'
                    }
                })

angular.module('app')
        .provider('isGranted', isGrantedP);

    isGrantedP.$inject = [];

    function isGrantedP() {

        this.$get = isGranted;

        isGranted.$inject = ['$q', '$log'];

        function isGranted($q, $log){
            $log.log('RESOLVE');
        }

    }

为什么不是每次都调用这个服务?是因为服务是单例吗?我应该如何进行?

【问题讨论】:

  • 确定没有调用resolve还是grantService返回了错误的值?
  • @AurélienThieriot 我确定它没有被调用,因为提供程序中的 $log 没有显示

标签: angularjs angular-ui-router ionic


【解决方案1】:

经过大量调查和测试,我找到了解决方案!

首先,让我们看看为什么它不起作用

如文档 (http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$stateProvider) 中所述,如果解析是字符串,则它对应于服务

factory - {string|function}:如果是字符串,那么它是服务的别名。 否则,如果是函数,则将其注入并返回将其视为的值 依赖。如果结果是一个承诺,它会在它的值是之前解决 注入控制器。

正如 angularjs 文档 (https://docs.angularjs.org/guide/providers) 中所述,所有服务都是单例的,这意味着它只会被实例化一次

注意:Angular 中的所有服务都是单例的。这意味着 注入器最多使用每个配方一次来创建对象。这 然后注入器缓存引用以备将来所有需要。

为什么重要?

因为解析不会在我们的服务中调用函数。他们只是使用实例化服务的返回值。 但是因为我们的服务只会被实例化一次,所以返回值总是一样的! (因为我们的服务初始化只被调用一次)

我们能做什么?

从我的测试中,我可以看到这样定义的解析:

resolve: {
                    myResolve: ['$log', function($log) {
                        $log.log('My Resolve!');
                    }]
                }

总是被执行,所以我们可以这样写来让它正常工作。

但是如果我想使用我的服务怎么办?

我发现能够使用我的服务并具有与此类似的语法的最佳工作解决方案:myResolve: 'myResolveService' 是这样声明我的解决方案:

resolve: {
                        myResolve: ['myResolveService', function(MyResolveService) {
                            myResolveService.log();
                        }]
                    }

我的服务是这样的:

angular.module('app')
        .factory('myResolve', myResolve);

    myResolve.$inject = ['$log'];

    function myResolve($log) {

        function service(){
            this.log = log;

            function log() {
                $log.log('My resolve!');
            }
        }

        return new service();

    }

此代码也可以适用于返回承诺的解析:

解决:

resolve: {
                            myResolve: ['myResolveService', function(MyResolveService) {
                                return myResolveService.check();
                            }]
                        }

服务:

angular.module('app')
        .factory('myResolve', myResolve);

    myResolve.$inject = ['$q', 'myService'];

    function myResolve($q, myService) {

        function service(){

            this.check = check;

            function check() {
                var defer = $q.defer();

                if (myService.check()) {
                    defer.resolve(true);
                } else {
                    defer.reject('rejected');
                }

                return defer.promise;
            }
        }

        return new service();

    }

【讨论】:

  • 很高兴知道。不错!
猜你喜欢
  • 2012-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多