与UI路由器角无限循环消化 [英] Angular infinite digest loop with ui-router
问题描述
我最初试图解决的问题是将用户重定向到登录页面,如果他们还没有登录,反之亦然。
我这样做有以下code
.RUN(函数($ rootScope,$ HTTP,AppService服务,$州){
$ rootScope在$('应用程序:refreshtoken',函数(rootScope,令牌){
如果(标记){
$ http.defaults.headers.common ['X-验证令牌'] =记号。
AppService.setAuthToken(标记);
AppService.resetLoginTimeout();
}
});
$ rootScope。在$('$ stateChangeSuccess',函数(){
$ http.get('/ API /心跳');
}); //这真的是有点相关...
$ rootScope。在('$ stateChangeStart'$,功能(即toState){
如果(toState.name ==='登录'){
如果(AppService.getIsLoggedIn()){
亦即preventDefault();
$ state.go(AppService.getRedirectPage());
}
}其他{
如果(!AppService.getIsLoggedIn()){
亦即preventDefault();
$ state.go('登录');
}
}
});
});
AppService服务
.factory('AppService服务',['$ rootScope,更衣室,$ HTTP,$州',
功能($ rootScope,更衣室,$ HTTP,$州){ VAR _isLoggedIn = locker.get('的loggedIn',虚假)
_authToken = locker.get('的authToken',NULL)
_roles = locker.get('角色',NULL)
_permissions = locker.get('权限',NULL)
_user = locker.get('用户',NULL)
_userid = locker.get('用户ID',NULL)
_user preFS = locker.get('用户preFS',NULL)
_时间到,
_timeoutId,
服务= {}; 如果(_authToken){
$ http.defaults.headers.common ['X-验证令牌'] = _authToken;
} service.setIsLoggedIn =功能(isLoggedIn){
_isLoggedIn = isLoggedIn;
this.doLogin();
broadcastLogin();
}; service.doLogin =功能(){
如果(_isLoggedIn){
locker.put({
的loggedIn:_isLoggedIn,
的authToken:_authToken,
角色:_roles,
权限:_permissions,
用户:_user,
用户preFS:_user preFS
});
}
}; service.doLogout =功能(CB){
_isLoggedIn = FALSE;
_authToken = NULL;
_roles = NULL;
_permissions = NULL;
_user = NULL;
_userid = NULL;
_user preFS = NULL; 删除$ http.defaults.headers.common ['X-验证令牌']; locker.clean(); CB();
};
service.getIsLoggedIn =功能(){
返回_isLoggedIn;
}; service.setAuthToken =功能(的authToken){
_authToken =的authToken;
locker.put({
的authToken:_authToken
}); }; service.getAuthToken =功能(){
返回_authToken;
}; service.setUserid =功能(用户ID){
locker.put(用户ID,用户ID);
_userid =用户标识;
}; service.getUserid =功能(){
返回_userid;
}; service.setUser =功能(用户){
_user =用户;
}; service.getUser =功能(){
返回_user;
}; service.setRoles =功能(角色){
_roles =角色;
}; service.getRoles =功能(){
返回_roles;
}; service.setPermissions =功能(权限){
_permissions =权限;
}; service.getPermissions =功能(){
返回_permissions;
}; service.setUser preferences =功能(preFS){
_user preFS = preFS;
}; service.getUser preferences =功能(){
返回_user preFS;
}; service.resetLoginTimeout =功能(){
如果(_timeoutId){
clearTimeout(_timeoutId);
}
_timeoutId = setTimeout的(函数(){
$ rootScope $广播(应用程序:logintimeoutwarn');。
},1000 * 60 * 4);
}; service.setTimedOut =功能(已逾时){
_timedout =已逾时;
}; service.getTimedOut =功能(){
返回_timedout;
}; service.extendSession =功能(){
$ http.get('/ API /心跳');
}; service.goDefaultUserPage =功能(){
VAR成功= FALSE;
如果(_user prefs.landingPage){
$ state.go(_user prefs.landingPage);
成功= TRUE;
}其他{
VAR permissionRoutes = {
方案:regimens.do',
路径:路径,
manage.users':'manageusers.do',
manage.practices':'managepractices.do',
'病人':'病人'
};
_.some(_permissions,功能(EL){
VAR状态= $ state.get(permissionRoutes [EL]);
如果(!state.abstract){
$ state.go(state.name);
成功= TRUE;
返回true;
}
});
}
返回成功;
}; service.getRedirectPage =功能(){
VAR页= FALSE;
如果(_user prefs.landingPage){
页= _user prefs.landingPage;
}其他{
VAR permissionRoutes = {
方案:regimens.do',
路径:路径,
manage.users':'manageusers.do',
manage.practices':'managepractices.do',
'病人':'病人'
};
_.some(_permissions,功能(EL){
VAR状态= $ state.get(permissionRoutes [EL]);
如果(!state.abstract){
页= state.name;
返回true;
}
});
}
返回页面;
}; 功能broadcastLogin(){
$ rootScope $广播(应用程序:loggedinstatus');。
} broadcastLogin(); 退换货服务; }
])
这code的伟大工程,直到我采取了非常具体的一套动作:
- 登录
- 关闭打开的标签或窗口
- 打开一个新标签,进入到应用程序
因为我在该应用程序仍处于登录状态,我有一个用户对象和一个有效的道理,但我正在逐渐错误:infdig无限$消化循环
。它最终解决并进入正确的状态,但它需要一段时间和路径闪烁(如果需要的话,我可以张贴的视频)。
我试着用 $ location.path
而不是 $ state.go
在 $ rootScope。在('$ stateChangeSuccess')
$回调,但问题仍然存在。
这并没有真正影响应用程序的功能,但它是烦人。我也真的不想改变我的更衣室存储会话存储,因为我想,如果他们关闭选项卡,并重新打开用户保持登录状态
我会说,这个问题是隐藏在不当的 如果
。在('$ stateChangeStart'的 $ rootScope $内声明...
检查这样的:
通过一般的建议:
的让我们重定向($ state.go())仅在需要 - 要么滚开事件侦听器的
块引用>$ rootScope。在$('$ stateChangeStart'...
如果(toState.name ==='登录'){
//要登录...不解决它在所有
返回;
}其次应检查:是用户身份验证的(并不会登陆)的
如果(AppService.getIsLoggedIn()){
//没有自动跳转,让他去......他被认证
返回;
}现在我们的状态,这是不登录,用户没有通过验证,我们可以清楚地拨打:
//这是必须的 - 停止电流
亦即preventDefault();
$ state.go('登录'); //去登录和一切将如我们预料的要工作
很详细的说明和工作的例子可以还发现这里 ...
The problem I was initially trying to solve was to redirect a user to the login page if they are not logged in and vice versa.
I did this with the following code
.run(function($rootScope, $http, AppService, $state) { $rootScope.$on('application:refreshtoken', function(rootScope, token) { if(token) { $http.defaults.headers.common['X-Auth-Token'] = token; AppService.setAuthToken(token); AppService.resetLoginTimeout(); } }); $rootScope.$on('$stateChangeSuccess', function() { $http.get('/api/heartbeat'); }); // This is the really pertinent bit... $rootScope.$on('$stateChangeStart', function(e, toState) { if(toState.name === 'login') { if(AppService.getIsLoggedIn()) { e.preventDefault(); $state.go(AppService.getRedirectPage()); } } else { if(!AppService.getIsLoggedIn()) { e.preventDefault(); $state.go('login'); } } }); });
AppService
.factory('AppService', ['$rootScope', 'locker', '$http', '$state', function ($rootScope, locker, $http, $state) { var _isLoggedIn = locker.get('loggedIn', false), _authToken = locker.get('authtoken', null), _roles = locker.get('roles', null), _permissions = locker.get('permissions', null), _user = locker.get('user', null), _userid = locker.get('userid', null), _userprefs = locker.get('userprefs', null), _timedout, _timeoutId, service = {}; if (_authToken) { $http.defaults.headers.common['X-Auth-Token'] = _authToken; } service.setIsLoggedIn = function (isLoggedIn) { _isLoggedIn = isLoggedIn; this.doLogin(); broadcastLogin(); }; service.doLogin = function () { if (_isLoggedIn) { locker.put({ loggedIn: _isLoggedIn, authtoken: _authToken, roles: _roles, permissions: _permissions, user: _user, userprefs: _userprefs }); } }; service.doLogout = function (cb) { _isLoggedIn = false; _authToken = null; _roles = null; _permissions = null; _user = null; _userid = null; _userprefs = null; delete $http.defaults.headers.common['X-Auth-Token']; locker.clean(); cb(); }; service.getIsLoggedIn = function () { return _isLoggedIn; }; service.setAuthToken = function (authToken) { _authToken = authToken; locker.put({ authtoken: _authToken }); }; service.getAuthToken = function () { return _authToken; }; service.setUserid = function (userid) { locker.put('userid', userid); _userid = userid; }; service.getUserid = function () { return _userid; }; service.setUser = function (user) { _user = user; }; service.getUser = function () { return _user; }; service.setRoles = function (roles) { _roles = roles; }; service.getRoles = function () { return _roles; }; service.setPermissions = function (permissions) { _permissions = permissions; }; service.getPermissions = function () { return _permissions; }; service.setUserPreferences = function (prefs) { _userprefs = prefs; }; service.getUserPreferences = function () { return _userprefs; }; service.resetLoginTimeout = function () { if (_timeoutId) { clearTimeout(_timeoutId); } _timeoutId = setTimeout(function () { $rootScope.$broadcast('application:logintimeoutwarn'); }, 1000 * 60 * 4); }; service.setTimedOut = function (timedout) { _timedout = timedout; }; service.getTimedOut = function () { return _timedout; }; service.extendSession = function () { $http.get('/api/heartbeat'); }; service.goDefaultUserPage = function () { var success = false; if (_userprefs.landingPage) { $state.go(_userprefs.landingPage); success = true; } else { var permissionRoutes = { 'regimens': 'regimens.do', 'pathways': 'pathways', 'manage.users': 'manageusers.do', 'manage.practices': 'managepractices.do', 'patients': 'patients' }; _.some(_permissions, function (el) { var state = $state.get(permissionRoutes[el]); if (!state.abstract) { $state.go(state.name); success = true; return true; } }); } return success; }; service.getRedirectPage = function () { var page = false; if (_userprefs.landingPage) { page = _userprefs.landingPage; } else { var permissionRoutes = { 'regimens': 'regimens.do', 'pathways': 'pathways', 'manage.users': 'manageusers.do', 'manage.practices': 'managepractices.do', 'patients': 'patients' }; _.some(_permissions, function (el) { var state = $state.get(permissionRoutes[el]); if (!state.abstract) { page = state.name; return true; } }); } return page; }; function broadcastLogin() { $rootScope.$broadcast('application:loggedinstatus'); } broadcastLogin(); return service; } ])
This code works great until I take a very specific set of actions:
- Login
- Close the open tab or window
- Open a new tab and go to the application
Since I am still logged in to the application, I have a user object and a valid token, but I am getting
error:infdig Infinite $digest Loop
. It eventually resolves and goes to the correct state, but it takes a while and the path flickers (I can post a video if needed).I tried using
$location.path
instead of$state.go
in the$rootScope.$on('$stateChangeSuccess')
callback, but the issue persists.This doesn't really affect the functioning of the application, but it is annoying. I also don't really want to change my locker storage to session storage because I want the user to stay logged in if they close the tab and reopen.
解决方案I would say, that the issue is hidden in the improper
if
statements inside of the$rootScope.$on('$stateChangeStart'...
Check this:With a general suggestion:
let's redirect ($state.go()) only if needed - else get out of the event listener
$rootScope.$on('$stateChangeStart' ... if (toState.name === 'login' ){ // going to login ... do not solve it at all return; }
Second check should be: is user authenticated (and NOT going to login)?
if(AppService.getIsLoggedIn()) { // do not redirect, let him go... he is AUTHENTICATED return; }
Now we have state, which is not login, user is not authenticated, we can clearly call:
// this is a must - stop current flow e.preventDefault(); $state.go('login'); // go to login
And all will work as we'd expected
Very detailed explanation and working example could be also found here...
这篇关于与UI路由器角无限循环消化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!