【问题标题】:AngularJS ui router $stateChangeStart with promise inifinite loop带有承诺无限循环的AngularJS ui路由器$ stateChangeStart
【发布时间】:2015-09-30 16:51:45
【问题描述】:

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

当 event.preventDefault() 是 $stateChangeStart 的第一行时,我不知何故陷入了无限循环。

我在 stackoverflow 上看到了多个问题的答案,比如 “将 event.preventDefault() 放在 else 中的 state.go 之前”。但随后控制器被触发,并且在返回 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 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;
    });
}

编辑:添加状态:

$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 中的更多代码,请告诉我!

【问题讨论】:

  • 您已经尝试添加以下行:$locationProvider.html5Mode(true);在您的路线配置中。并将此元数据添加到 html 标头:。这会驱逐 URL 末尾的 uggly /#。
  • 哦,是的,我忘记了 html5mode() 记录,谢谢!

标签: javascript angularjs angular-ui-router


【解决方案1】:

$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 注入。

来自wiki

如果您想在实例化子节点之前等待 promise 被解析,则必须将解析键注入子状态。

【讨论】:

  • 其实我两者都有。因为解析只触发一次(页面第一次加载)。或者有没有办法确保总是触发解析?
  • 是的,您可以使用$state.go()reload 选项。但是,如果您有其他解析,那将是低效的,因为它们也会被重新加载。 angular-ui.github.io/ui-router/site/#/api/…
  • 既然缓存了_identity,为什么每次都要触发呢?
  • 我在问题中添加了我的状态。我不希望每次都触发解析,我希望在加载任何状态之前进行某种身份验证检查。这就是我使用 stateChangeStart 的原因,它会在每次状态更改时触发。调试的时候可以看到当promise返回的时候,state.go会被触发,那么你确定stateChangeStart不会等待promise吗?
  • 是的,您的then 块中的代码已执行。我的意思是,无论 promise 的状态如何,状态更改都会继续进行,这就是为什么您会看到控制器在 promise 解决之前触发。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-06
  • 1970-01-01
  • 2017-01-12
  • 1970-01-01
  • 2014-10-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多