How to redirect in a ui-router resolver?
I am trying to redirect inside a ui-router resolve and wanted to know if there is a way to reroute in a router resolver. Currently this does not work as one would think.
resolver(auth, $state){
if(!auth.isLoggedIn()){
$state.go('noLoggedInPath');
}
}
How does one redirect in a resolver correctly ?
My temp hack is this but I am not comfortable with it.
resolver(auth, $state, $timeout){
if(!auth.isLoggedIn()){
$timeout(function () {
$state.go('noLoggedInPath');
}, 0);
}
}
Solution 1:
Yauheni's answer does work, but to get around the weird timeout thing, you can reject the promise, and catch that in the $stateChangeError event, and do your redirect there. Like so...
state('admin', {
resolve: {
auth: function(UserService, $q, permissionService) {
var deferred = $q.defer();
return UserService.load().then(function(user){
if (permissionService.can(user, {goTo: state})) {
return deferred.resolve({});
} else {
return deferred.reject({redirectTo: 'some_other_state'});
}
});
}
}
});
And then ui-router always broadcasts "stateChangeError", so you can do something like this..
$rootScope.$on('$stateChangeError', function(evt, to, toParams, from, fromParams, error) {
if (error.redirectTo) {
$state.go(error.redirectTo);
} else {
$state.go('error', {status: error.status})
}
})
Solution 2:
You can return a promise from your resolver
function that will indicate whether to continue navigating to the state or not. If you decide to navigate somewhere else - reject the promise and specify the proper state:
resolver($q, $state, $timeout, auth) {
var deferred = $q.defer();
// $timeout is an example; it also can be an xhr request or any other async function
$timeout(function() {
if (!auth.isLoggedIn()) {
// user is not logged, do not proceed
// instead, go to a different page
$state.go('noLoggedInPath');
deferred.reject();
} else {
// everything is fine, proceed
deferred.resolve();
}
});
return deferred.promise;
}
Plunkr here.
UPD: updated code and added plunkr. Looks like it only works if you put it inside a timeout function.
Solution 3:
I use this
function Check($state, $q) {
var deferred = $q.defer();
if (condition) {
deferred.resolve();
}
else {
deferred.reject();
}
return deferred.promise.catch(function () { $state.go('path'); });
}
Solution 4:
This is what I actually do, and I can't find a better solution
resolver($q, $timeout, myService) {
if(!areParameterValuesValid() || !isEverythingLogicallyOk()){
var deferred = $q.defer();
$timeout(function() {
$state.go('somewhere');
deferred.reject();
});
return deferred.promise;
} else {
return myService.loadSomething(passingSomeParams);
}
}
Solution 5:
I think a much cleaner answer is to return an already rejected promise like so:
resolver(auth, $state, $q){
if(!auth.isLoggedIn()){
$state.go('noLoggedInPath');
// Return rejected promise
return $q.reject();
}
return true;
}