Angular ui-router $state.go is not redirecting inside resolve

All we need is an easy explanation of the problem, so here it is.

In my angularjs app, I am checking if user lands on landing page and is already authenticated, then redirect him to home page.

.state('landingpage', {
            abstract: "true",
            url: "/landingpage",
            templateUrl: "app/landingpage/landingpage.html",
            resolve: {
                AutoLoginCheck: ['$state', '$window', function ($state, $window) {

                    if($window.localStorage.access_token != null)
                    {
                        if($window.sessionStorage.access_token == null) {
                            $window.sessionStorage.access_token = $window.localStorage.access_token;
                        }
                        UserInfoService.SetUserAuthenticated(true);

                        // it is not redirecting
                        return $state.go('app.home');

                    }
                }]
            }
        })

The problem is that though all the resolve code is successfully run, user is not getting redirected to app.home. Can someone tell why this happens?

Note: The state ‘app’ also has a resolve in which it fetches the data to be displayed in ‘app.home’ state.

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

.state('landingpage', {
            abstract: "true",
            url: "/landingpage",
            templateUrl: "app/landingpage/landingpage.html",
            resolve: {
                AutoLoginCheck: ['$state','$window', '$q','$timeout', function ($state, $window,$q,$timeout) {

                    if($window.localStorage.access_token != null)
                    {
                        if($window.sessionStorage.access_token == null) {
                            $window.sessionStorage.access_token = $window.localStorage.access_token;
                        }
                        UserInfoService.SetUserAuthenticated(true);


                        $timeout(function() {
                           $state.go('app.home')
                        },0);
                        return $q.reject()

                    }
                }]
            }
        })

This would work for you.

Method 2

There can be two solutions to your problem

  • Firstly you can emit an event and the listener will handle your state transition. You can implement the listener in anywhere in a parent controller

  • Secondly you can implement the $stateChangeStart hook and check your redirection condition there

    $rootScope.$on('$stateChangeStart', function (event, toState) {      
         if (toState.name === 'landingpage') {              
           if (!isAuthenticated()) { // Check if user allowed to transition                  
                event.preventDefault();   // Prevent migration to default state                  
                $state.go('home.dashboard');           
            }
          }
    });
    

Method 3

You can use $location.url('/') instead.

Method 4

You can use resolve to provide your controller with content or data that is custom to the state. resolve is an optional map of dependencies which should be injected into the controller.

You could have a controller that checks for the AuthState and have the redirection accordingly.

     .state('landingpage', {
        abstract: "true",
        url: "/landingpage",
        templateUrl: "app/landingpage/landingpage.html",
        resolve: {
            AutoLoginCheck: ['$window', function ($window) {

                if($window.localStorage.access_token != null)
                {
                    if($window.sessionStorage.access_token == null) {
                        $window.sessionStorage.access_token = $window.localStorage.access_token;
                    }

                   //assuming userInfoService does the authentication
                    var isAuthenticated = userInfoService.SetUserAuthenticated(true);
                    return isAuthenticated;

                }
            }]
        },
        controller: ['$state','AutoLoginCheck', function($state, AutoLoginCheck){
          if(AutoLoginCheck){
            //authenticated
            $state.go('app.home');
          } else {
            //redirect to unauthenticated page
            $state.go('....');
          }
        }]
    })

Method 5

This is an old thread, but I use $location.path() to accomplish redirection inside of a state.resolve() block

Method 6

Anyway resolve waiting for promise state . Best thing what you can do is return promise and add timeout for your state:

resolve: {
    AutoLoginCheck: ['$state', '$window', '$timeout', '$q', function ($state, $window, $timeout, $q) {
        var deferred = $q.defer();
        if(user.isLogin()){
             deferred.resolve();
        }else{
          $timeout(function(){
            $state.go('app.home');
          }
          deferred.reject();
        }
        return deferred.promise;
    }]

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply