Reputation: 1914
I have a run block that is querying my server to check if the user is authenticated.
.run(function($http, userService){
var base_url = 'http://server.com:3000';
$http.get(base_url + '/users/isloggedin')
.success(function(data, status, headers, config){
userService.setUserData(data.userData);
userService.setIsUserLoggedIn(true);
});
})
Later, I have another run that will require info from the first run block. The problem with this is that my run code has async code and I am not getting the true value at the first time to userService.getIsUserLoggedIn().
How can I tell angularjs to execute the second run block only after the first one has been completed?
The second run block:
.run(function($rootScope, $location, $state, userService){
//Run to handle authentication
var authOnly = ['/painel'];
var unAuthOnly = ['/home'];
var checkAuthRoute = function(url){
var exist = authOnly.indexOf(url);
return exist > -1;
};
var checkUnAuthRoute = function(url){
var exist = unAuthOnly.indexOf(url);
return exist > -1;
};
$rootScope.$on('$stateChangeStart', function(evt, toState, toParams, fromState, fromParams){
console.log(toState.url + ' ' + fromState.url + ' - ' + userService.getIsUserLoggedIn());
if(!userService.getIsUserLoggedIn() && checkAuthRoute(toState.url)){
console.log('Aqui..');
evt.preventDefault();
$state.go('login');
}
});
})
Thanks
Upvotes: 1
Views: 57
Reputation: 3480
You can use callbacks to make chain async requests in Javascript. Something like this might work:
.run(function($http, $rootScope, $location, $state, userService){
var base_url = 'http://server.com:3000';
$http.get(base_url + '/users/isloggedin')
.success(function(data, status, headers, config){
userService.setUserData(data.userData);
userService.setIsUserLoggedIn(true);
handleAuth($rootScope, $location, $state, userService);
});
})
And define this function before the .run
code from above:
function handleAuth($rootScope, $location, $state, userService){
var authOnly = ['/painel'];
var unAuthOnly = ['/home'];
var checkAuthRoute = function(url){
var exist = authOnly.indexOf(url);
return exist > -1;
};
var checkUnAuthRoute = function(url){
var exist = unAuthOnly.indexOf(url);
return exist > -1;
};
$rootScope.$on('$stateChangeStart', function(evt, toState, toParams, fromState, fromParams){
console.log(toState.url + ' ' + fromState.url + ' - ' + userService.getIsUserLoggedIn());
if(!userService.getIsUserLoggedIn() && checkAuthRoute(toState.url)){
console.log('Aqui..');
evt.preventDefault();
$state.go('login');
}
});
}
Or a much more popular alternative (to prevent constant chaining of callbacks which makes code unreadable--aka the Pyramid of Doom), is to use Promises.
A promise takes an async function and returns a promise, which you can use to chain requests (ex. the $http method returns a promise that you're using called success
). It is not available in ECMAScript 5, but will be in 6. People have made a bunch of implementations of Promises, such as Kris Kowal's Q
, and Angular has a stripped down version of this library called $q
.
Upvotes: 1
Reputation: 3111
Because this is async call, technically first block is finished, but the call(s) inside it wasn't. The only thing that comes to my mind is adding promise into userService and communicate through it:
.run(function($http, $q, userService){
var base_url = 'http://server.com:3000';
var deferred = q.defer();
$http.get(base_url + '/users/isloggedin')
.success(function(data, status, headers, config){
userService.setUserData(data.userData);
userService.setIsUserLoggedIn(true);
deferred.resolve();
});
userService.setPromise(deferred.promise);
})
And in second run:
.run(function(userService){
userService.getPromise().then(function(){
//code that requires first run to finish
});
})
But if somewhere you need code from second run to finish(I mean do smth only after second run), it will require same structure again, and that's not really good, so you need to change the logic.
Upvotes: 0