Timo Timo - 4 months ago 32
AngularJS Question

Angular state change after a promise

I'm not sure if this is a duplicate or not, but I didn't manage to find anything that worked for me, so I'm posting this question.

I have a situation where I need to get values from database before directing user to certain routes, so I could decide what content to show.

If I move

e.preventDefault()
right before
$state.go(..)
then it works, but not properly. Problem is that it starts to load default state and when it gets a response from http, only then it redirects to
main.home
. So let's say, if the db request takes like 2 seconds, then it takes 2 seconds before it redirects to
main.home
, which means that user sees the content it is not supposed to for approximately 2 seconds.

Is there a way to prevent default at the beginning of state change and redirect user at the end of state change?
Also, if we could prevent default at the beginning of state change, then how could we continue to default state?

(function(){
"use strict";
angular.module('app.routes').run(['$rootScope', '$state', '$http', function($rootScope, $state, $http){
/* State change start */
$rootScope.$on('$stateChangeStart', function(e, to, toParams, from, fromParams){
e.preventDefault();
$http
.get('/url')
.error(function(err){
console.log(err);
})
.then(function(response){
if( response.data === 2 ){
// e.preventDefault()
$state.go('main.home');
}
// direct to default state
})
}
}]);
});

Answer

You could add a resolve section to your $stateProviderConfig.

Inside the resolve you can make a request to the databse and check required conditions. If case you don't want user to acces this page you can use $state.go() to redirect him elsewhere.

Sample config:

.state({
    name: 'main.home',
    template: 'index.html',
    resolve: {
        accessGranted: ['$http', '$state',
            function(http, $state) {
                let deffered = $q.defer();
                $http({
                    method: 'GET',
                    url: '/url'
                }).then(function(data) {
                    if (data === 2) {
                        // ok to pass the user
                        deffered.resolve(true);
                    } else {
                        //no access, redirect
                        $state.go('main.unauthorized');
                    }
                }, function(data) {
                    console.log(data);
                    //connection error, redirect
                    $state.go('main.unauthorized');
                });
                return deffered.promise;
            }
        ]
    }
});

Documentation of the resolve is available here

Note that you could use Promise object instead of $q service in case you don't need to support IE