55

I have 4 states: dashboard, dahboard.main, dashboard.minor, login. dashboard is abstract and it is a parent state for .minor and .main states. Below is my code:

.state('dashboard', {
        url: "/dashboard",
        abstract: true,
        templateUrl: "views/dashboard.html",
        resolve: {
            auth: function ($q, authenticationSvc) {
                var userInfo = authenticationSvc.getUserInfo();
                if (userInfo) {
                    return $q.when(userInfo);
                } else {
                    return $q.reject({ authenticated: false });
                }
            }
        },
        controller: "DashboardCtrl",
        data: { pageTitle: 'Example view' }
    })
    .state('dashboard.main', {
        url: "",
        templateUrl: "views/main.html",
        controller: "DashboardCtrl",
        data: { pageTitle: 'Main view' }
    })

As you see in dashboard state I have resolve option. By this I would like to redirect user to login page if he is not authorized. For this reason I use special authenticationSvc service:

.factory("authenticationSvc", ["$http", "$q", "$window", function ($http, $q, $window) {
    var userInfo;

    function login(email, password) {
        var deferred = $q.defer();

        $http.post("/api/login", { email: email, password: password })
            .then(function (result) {
                if(result.data.error == 0) {
                    userInfo = {
                        accessToken: result.data.accessToken
                    };
                    $window.sessionStorage["userInfo"] = JSON.stringify(userInfo);
                    deferred.resolve(userInfo);
                }
                else {
                    deferred.reject(error);
                }
            }, function (error) {
                deferred.reject(error);
            });

        return deferred.promise;
    }
    function getUserInfo() {
        return userInfo;
    }
    return {
        login: login,
        logout: logout,
        getUserInfo: getUserInfo
    };
}]);

I check auth value in config :

.run(function($rootScope, $location, $state) {
    $rootScope.$state = $state;
    $rootScope.$on("routeChangeSuccess", function(userInfo) {
        consol.log(userInfo);
    });
    $rootScope.$on("routeChangeError", function(event, current, previous, eventObj) {
        if(eventObj.authenticated === false) {
            $state.go('login');
        }
    });
});

But unfortunately when I go to my website root or dashboard state I get an empty page. What is wrong with this code? Thanks!

1
  • 1
    The event names are actually $routeChangeSuccess and $routeChangeError (note the leading $)...couldn't be as simple as that? Commented Nov 30, 2014 at 10:23

3 Answers 3

77

The point is, do not redirect if not needed === if already redirected to intended state. There is a working plunker with similar solution

.run(function($rootScope, $location, $state, authenticationSvc) {


    $rootScope.$on( '$stateChangeStart', function(e, toState  , toParams
                                                   , fromState, fromParams) {

        var isLogin = toState.name === "login";
        if(isLogin){
           return; // no need to redirect 
        }

        // now, redirect only not authenticated

        var userInfo = authenticationSvc.getUserInfo();

        if(userInfo.authenticated === false) {
            e.preventDefault(); // stop current execution
            $state.go('login'); // go to login
        }
    });
});

Check these for similar explanation:

Sign up to request clarification or add additional context in comments.

2 Comments

Note to others: The code in this great answer is what you need. The referenced Plunkr is nice, but is too verbose.
This example only works in legacy version (0.2). For newer versions (1.x), please read this migration guide: ui-router.github.io/guide/ng1/…
4

Since you are using UI-Router module, you should be using $stateChangeStart, $stateChangeSuccess events.

Check this link for more: https://github.com/angular-ui/ui-router/issues/17

Also there is a typo in consol.log(userInfo) in console.

Check the console in your chrome-dev-tools. It will give idea if something else is missing.

3 Comments

Thanks! Now when I go to root of my website without authorization I am being redirected to login page, however when I go to dashboard state I have an empty page.
Have you checked what the console of the browser says..?
I have the same scenario today, where my dashboard state has a resolve:; however, inside my app.js watcher ($rootScope.$on('$stateChangeStart'), it hangs on event.preventDefault(); . I get the Angular Infinite Loop error. Why is that ?
0

Beware that actually $stateChangeSuccess event is deprecated and no longer available in angular-ui-route package. Now, this behavior is handled by transition hooks. You could achieve your purpose using $transitions.onStart as follows:

run.$inject = ['$transitions', 'authenticationSvc'];
function run($transitions, authenticationSvc) {

  $transitions.onStart({}, function (trans) {
    var userInfo = authenticationSvc.getUserInfo();

    var $state = trans.router.stateService;

    if(userInfo.authenticated === false) {
        $state.go('login'); // go to login
    }
  });
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.