Hom*_*man 45 promise angularjs angular-ui-router
我希望防止在rails设置超时时发生的一些闪烁,但是角度在资源的下一个授权错误之前不会知道.
发生的是模板被渲染,一些ajax调用资源发生,然后我们被重定向到rails设计登录.我宁愿在每次状态更改时对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'
}
})
});
Run Code Online (Sandbox Code Playgroud)
在呈现新模板之前,如何根据承诺的结果中断状态转换?
Joe*_*gan 46
我知道这场比赛已经很晚了,但我想把我的意见抛在脑后,讨论一下我认为是"暂停"状态改变的好方法.根据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;
}
]
});
Run Code Online (Sandbox Code Playgroud)
这将确保状态更改适用于要在API调用完成时完成的承诺以及基于API返回的所有决策.在允许导航新页面之前,我已经使用它来检查服务器端的登录状态.当API调用解析时,我使用"event.preventDefault()"来停止原始导航,然后路由到登录页面(用if state.name!="login"围绕整个代码块)或允许用户继续简单地解决延迟的承诺而不是尝试使用旁路布尔值和preventDefault().
虽然我确定原来的海报早已解决了他们的问题,但我真的希望这有助于其他人.
编辑
我想我不想误导别人.如果您不确定您的状态是否具有解析对象,那么代码应该是什么样子:
$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;
}
]
});
Run Code Online (Sandbox Code Playgroud)
编辑2
为了使这个适用于没有解析定义的状态,您需要在app.config中添加它:
var $delegate = $stateProvider.state;
$stateProvider.state = function(name, definition) {
if (!definition.resolve) {
definition.resolve = {};
}
return $delegate.apply(this, arguments);
};
Run Code Online (Sandbox Code Playgroud)
这样做if (!toState.resolve) { toState.resolve = {} };在stateChangeStart似乎没有工作,我认为它已被初始化后,用户界面路由器不接受决心字典.
Aiv*_*ras 27
我相信你在找 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
})
Run Code Online (Sandbox Code Playgroud)
虽然我可能会resolve在状态配置中使用@charlietfl建议
编辑:
所以我有机会在状态变化事件中使用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
}
}
)
}
Run Code Online (Sandbox Code Playgroud)
编辑
较新的文档包含一个示例,说明sync()在preventDefault调用后用户应该如何继续,但是如果使用了$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();
});
});
Run Code Online (Sandbox Code Playgroud)
小智 24
这是我对这个问题的解决方案.它运作良好,并且在这里有一些其他答案的精神.它只是清理了一点.我正在根范围上设置一个名为'stateChangeBypass'的自定义变量,以防止无限循环.我还要检查状态是否为"登录",如果是,则始终允许.
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');
}
});
});
}
Run Code Online (Sandbox Code Playgroud)
oor*_*ori 15
由于$ urlRouter.sync()不能与stateChangeStart一起使用,这里有一个替代方案:
var bypass;
$rootScope.$on('$stateChangeStart', function(event,toState,toParams) {
if (bypass) return;
event.preventDefault(); // Halt state change from even starting
var meetsRequirement = ... // Perform custom logic
if (meetsRequirement) { // Continue with the update and state transition if logic allows
bypass = true; // bypass next call
$state.go(toState, toParams); // Continue with the initial state change
}
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
38018 次 |
| 最近记录: |