title: Angular infinite digest loop with ui-router
body: <p>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.</p>
  
  <p>I did this with the following code</p>
  
  <pre><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');
              }
          }
      });
   });
  </code></pre>
  
  <h2>AppService</h2>
  
  <pre><code>.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;
  
    }
  ])
  </code></pre>
  
  <p>This code works great until I take a very specific set of actions:</p>
  
  <ol>
  <li>Login</li>
  <li>Close the open tab or window</li>
  <li>Open a new tab and go to the application</li>
  </ol>
  
  <p>Since I am still logged in to the application, I have a user object and a valid token, but I am getting <code>error:infdig Infinite $digest Loop</code>. 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).</p>
  
  <p>I tried using <code>$location.path</code> instead of <code>$state.go</code> in the <code>$rootScope.$on('$stateChangeSuccess')</code> callback, but the issue persists.</p>
  
  <p>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.</p>