Reputation: 2748
Is it possible to use promises right in the resolve property of the router? I want to use a service to check if user has permission to access the page in the route resolve. Example:
$stateProvider
.state('user', {
url: '/user',
templateUrl: 'app/views/user/views/user.html',
controller: 'UserCtrl',
controllerAs: 'vm',
resolve: {
security: ['$state', 'userService','messageService','$location', function ($state, userService, messageService, $location) {
userService.checkUserAndRole("user").then(function(data){
var data = userService.checkUserAndRole("user");
if (data.access === false) {
messageService.errorMsg(data.message);
var route = data.route ? data.route:$location.path();
$state.go(route);
});
}]
}
});
I am using $q service in userService to return a promise
function checkUserAndRole(page){
var defer = $q.defer();
var response = {};
if(!ROLE[page]){
response.access = false;
response.message = "Page is not defined in ROLE config. Please tell admin to correct this!";
response.route = "login";
defer.resolve(response);
}
if(!user.roles){
response.access = false;
response.message = "Logged in user does not seem to have any role data defined. That is why you are redirected";
response.route = "/";
defer.resolve(response);
}
if(!helperService.arrayIntersect(ROLE[page],user.roles)){
response.access = false;
response.message = "You don't have a permission to access '/"+page+"' url";
defer.resolve(response);
}
response.access = true;
response.message = "";
response.route = "";
return defer.promise;
}
If I don't use promises but return the data from the service immediately all works well but on refresh I still get invalid results since user data from service is fetched via $http and the data is not there yet when the route is resolved.
Upvotes: 0
Views: 1631
Reputation: 48968
Resolve functions work with promises, but it is important to return the promise to the resolver function.
$stateProvider
.state('user', {
url: '/user',
templateUrl: 'app/views/user/views/user.html',
controller: 'UserCtrl',
controllerAs: 'vm',
resolve: {
security: ['$state', 'userService','messageService','$location', function ($state, userService, messageService, $location) {
//RETURN the promise
return (
userService.checkUserAndRole("user")
.then(function(data){
if (data.access === false) {
messageService.errorMsg(data.message);
var route = data.route ? data.route:$location.path();
$state.go(route);
});
);
}]
}
});
By failing to return the promise to the resolver function, the router resolves security
to null
without waiting for the promise to complete.
Also the checkUserAndRole
function fails to resolve the $q.defer
in the case where none of the if
conditions are true. The code needs to be rewritten.
function checkUserAndRole(page){
var response = {};
var promise = $q.when();
if(!ROLE[page]){
response.access = false;
response.message = "Page is not defined in ROLE config. Please tell admin to correct this!";
response.route = "login";
promise = $q.when(response);
} else if(!user.roles) {
response.access = false;
response.message = "Logged in user does not seem to have any role data defined. That is why you are redirected";
response.route = "/";
promise = $q.when(response);
} else if(!helperService.arrayIntersect(ROLE[page],user.roles)){
response.access = false;
response.message = "You don't have a permission to access '/"+page+"' url";
promise = $q.when(response);
} else {
response.access = true;
response.message = "";
response.route = "";
promise = $q.when(response);
};
return promise;
}
Avoid $q.defer
as it is prone to coding errors. Instead use $q.when
to create a promise from a value.
Upvotes: 1