与UI路由器角无限循环消化 [英] Angular infinite digest loop with ui-router

查看:137
本文介绍了与UI路由器角无限循环消化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最初试图解决的问题是将用户重定向到登录页面,如果他们还没有登录,反之亦然。

我这样做有以下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的伟大工程,直到我采取了非常具体的一套动作:


  1. 登录

  2. 关闭打开的标签或窗口

  3. 打开一个新标签,进入到应用程序

因为我在该应用程序仍处于登录状态,我有一个用户对象和一个有效的道理,但我正在逐渐错误: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:

  1. Login
  2. Close the open tab or window
  3. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆