I have an Angular app using UI Router where I\'m trying to validate a user\'s token, if one exists, when the app runs. I am also checking that the user has permission to acc
I guess it's too late for answering this question, but I want to comment here for someone who may need a little idea.
I've tried to do almost same thing for a long time and I stopped doing that. I don't think stateChangeStart
listener is reliable to use.
I think the best way to do your what you want is decorating $state.go
using $provide
service. Here is an example:
/* config your angular app */
.config(function($provide) {
$provide.decorator('$state', function($delegate) {
var myState = $delegate;
// Rename original 'go' method
myState.originalGo = myState.go;
myState.go = function(toState, toParams, options) {
/*
* Do what you want to do :)
*/
this.originalGo(toState, toParams, options);
};
return $delegate;
});
With this approach, you can do whatever you want before $stateChangeStart
.
I hope it helps.
You should call $urlRouter.sync()
after you have got user data. Also you might want to protect $stateChangeStart
by using event.preventDefault()
in case when user was not obtained.
I have found a very good way to make this work properly and not rely on resolve at all in another answer here. Here is the code:
rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState) {
if (dataService.isInitialized()) {
proceedAsUsual(); // Do the required actions based on the data you received in the service
}
else {
event.preventDefault();
dataService.intialize().success(function () {
$state.go(toState, toParams);
});
}
});
Then you can just remember that your data is already initialized in the service the way you like, e.g.:
function dataService() {
var initialized = false;
return {
initialize: initialize,
isInitialized: isInitialized
}
function intialize() {
return $http.get(...)
.success(function(response) {
initialized=true;
});
}
function isInitialized() {
return initialized;
}
};
I'd create a function in your Auth
service that returns a promise. Later, resolve (authorized) or reject (not authrized) that deferred. Then use it on the resolve
property of your route definitions
$stateProvider.state('stateName',{
...
...
resolve: {
isAuthorized: function(Auth){
return Auth.checkAuthorization();
}
}
})
To support subsequent checks you could maintain a promise within the service This might look like:
myApp.service('Auth',function($http,$q){
var authStatusDeferred = $q.defer();
this.checkAuthorization = function(){
return authStatusDeferred.promise;
};
this.validateToken = function(user){
var isValid = false;
//..do validation stuff
if(isValid) authStatusDeferred.resolve();
//Otherwise state change will not happen..
};
});
oh, sorry about no coffee