我想防止当rails设备超时时发生的一些闪烁,但是angular直到资源的下一次授权错误才知道。
发生的情况是,模板被呈现,一些ajax调用资源,然后我们被重定向到rails devise进行登录。我宁愿在每次状态改变时对rails执行ping,如果rails会话已经过期,那么我会在模板呈现之前立即重定向。
ui-router具有可以放在每条路由上的解决方案,但这看起来一点也不干燥。
我有的是这个。但是,只有在状态已经转换之后,才能解析承诺。
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){
//check that user is logged in
$http.get('/api/ping').success(function(data){
if (data.signed_in) {
$scope.signedIn = true;
} else {
window.location.href = '/rails/devise/login_path'
}
})
});在基于promise的结果呈现新模板之前,我如何中断状态转换?
发布于 2015-10-22 19:33:01
我知道这是非常晚的游戏,但我想抛出我的观点,并讨论我认为是一个很好的方式来“暂停”状态变化。根据angular-ui-router的文档,作为promise的状态的"resolve“对象的任何成员都必须在状态加载完成之前进行解析。所以我的功能性(尽管还没有完善)的解决方案,是在“$stateChangeStart”上的"toState“的resolve对象中添加一个promise:
例如:
$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
toState.resolve.promise = [
'$q',
function($q) {
var defer = $q.defer();
$http.makeSomeAPICallOrWhatever().then(function (resp) {
if(resp = thisOrThat) {
doSomeThingsHere();
defer.resolve();
} else {
doOtherThingsHere();
defer.resolve();
}
});
return defer.promise;
}
]
});这将确保状态更改适用于要解决的承诺,这是在API调用完成时完成的,并且做出了基于API返回的所有决策。在允许导航到新页面之前,我已经使用它检查了服务器端的登录状态。当API调用解析时,我要么使用"event.preventDefault()“来停止原始导航,然后路由到登录页面(用if state.name !=”login“括起整个代码块),要么允许用户通过简单地解析延迟承诺来继续,而不是尝试使用绕过布尔值和preventDefault()。
虽然我确信最初的帖子早就解决了他们的问题,但我真的希望这能对其他人有所帮助。
编辑
我想我不想误导别人。如果你不确定你的状态是否有resolve对象,下面是代码应该是什么样子的:
$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
if (!toState.resolve) { toState.resolve = {} };
toState.resolve.pauseStateChange = [
'$q',
function($q) {
var defer = $q.defer();
$http.makeSomeAPICallOrWhatever().then(function (resp) {
if(resp = thisOrThat) {
doSomeThingsHere();
defer.resolve();
} else {
doOtherThingsHere();
defer.resolve();
}
});
return defer.promise;
}
]
});编辑2个
为了使其适用于没有解析定义的州,您需要在app.config中添加以下内容:
var $delegate = $stateProvider.state;
$stateProvider.state = function(name, definition) {
if (!definition.resolve) {
definition.resolve = {};
}
return $delegate.apply(this, arguments);
};在stateChangeStart中执行if (!toState.resolve) { toState.resolve = {} };似乎不起作用,我认为ui-router在初始化后不接受resolve判据。
发布于 2013-11-22 03:28:21
我相信你是在找event.preventDefault()
注意:使用event.preventDefault()可以防止转换的发生。
$scope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams){
event.preventDefault();
// transitionTo() promise will be rejected with
// a 'transition prevented' error
})尽管我可能会像@charlietfl建议的那样在状态配置中使用resolve
编辑
因此,我有机会在状态更改事件中使用preventDefault(),下面是我所做的:
.run(function($rootScope,$state,$timeout) {
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams){
// check if user is set
if(!$rootScope.u_id && toState.name !== 'signin'){
event.preventDefault();
// if not delayed you will get race conditions as $apply is in progress
$timeout(function(){
event.currentScope.$apply(function() {
$state.go("signin")
});
},300)
} else {
// do smth else
}
}
)
}编辑
Newer documentation包含了一个如何在调用preventDefault后使用sync()以继续的示例,但是示例使用了$locationChangeSuccess事件,这对我和评论者来说是不起作用的,而使用下面的示例中的$stateChangeStart,取自带有更新事件的文档:
angular.module('app', ['ui.router'])
.run(function($rootScope, $urlRouter) {
$rootScope.$on('$stateChangeStart', function(evt) {
// Halt state change from even starting
evt.preventDefault();
// Perform custom logic
var meetsRequirement = ...
// Continue with the update and state transition if logic allows
if (meetsRequirement) $urlRouter.sync();
});
});发布于 2015-03-03 16:23:10
这是我对这个问题的解决方案。它工作得很好,并且符合这里的一些其他答案的精神。只是稍微清理了一下。我在根作用域上设置了一个名为'stateChangeBypass‘的自定义变量,以防止无限循环。我还在检查状态是否为“login”,如果是,则总是允许的。
function ($rootScope, $state, Auth) {
$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/questions/20094273
复制相似问题