I am using AngularJS with Meteor and wanted to redirect users with unverified emails to the sign in page. I have created a sign in view in /client/routes.js
:
app.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('/');
$stateProvider
.state('signin', {
url:'/signin',
views: {
main: {
templateUrl: 'client/views/profile/signin.tpl'
}
}
})
Note that there are other states I am not listing for brevity sake.
Now, I want to redirect users to this sign in page if their emails have not been verified. How do I modify the example below from UI-Router FAQs to meet my needs? Other solutions not using the example below are acceptable to me as long as they address the issue at hand.
Example: Uses the data object on the state config to define a rule
function that will run logic against the user (here using an example
service called $currentUser). The $stateChangeStart handler catches
all state transition and performs this rule check before allowing the
transition, potentially blocking it and/or redirecting to a different
state.
app.config(function($stateProvider) {
$stateProvider.state('privatePage', {
data: {
rule: function(user) {
// ...
}
});
});
app.run(function($rootScope, $state, $currentUser) {
$rootScope.$on('$stateChangeStart', function(e, to) {
if (!angular.isFunction(to.data.rule)) return;
var result = to.data.rule($currentUser);
if (result && result.to) {
e.preventDefault();
// Optionally set option.notify to false if you don't want
// to retrigger another $stateChangeStart event
$state.go(result.to, result.params, {notify: false});
}
});
});
The example from the FAQ attempts to create a general way to add a rule to any page. Let's keep it simple:
app.run(function($rootScope, $state, UserService) {
$rootScope.$on('$stateChangeStart', function(event, toState) {
// don't check auth on login routes
if (["signin"].indexOf(toState.name) === -1) {
if (UserService.doesNotHaveVerifiedEmail()) {
event.preventDefault();
$state.go('signin');
return;
}
}
}
});
Anytime a state is loaded and it's not the signin state, you check if the user is verified (depends on your application, here I am injecting a UserService which I assume has knowledge about the user's status) and if not, you prevent that state change and redirect them to the signin page.
You can use the resolve
functionality provided by angular-ui-router to check email verification of current user before the state is resolved. Here's how the code will look like:
app.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
var isVerified = ['User', '$state', '$q',
function(User, $state, $q) {
var d = $q.defer();
var loginPromise = User.getVerificationStatus();
loginPromise.then(
function(response) {
d.resolve(response);
},
function(error) {
$state.go('login');
});
return d.promise;
}
];
$urlRouterProvider.otherwise('/');
$stateProvider
.state('signin', {
url: '/signin',
views: {
main: {
templateUrl: 'client/views/profile/signin.tpl'
}
}
})
.state('home', {
url: '/home',
views: {
main: {
templateUrl: 'client/views/profile/home.tpl'
}
},
resolve: {
verified: isVerified
}
});
}
]);
Here home
state checks for the verification before resolving. I have injected a service User
which will arrange the information whether user is verified or not.
You can add resolve property to only those states where you want to check verification status. In this way this is better than checking on $stateChangeStart
event which will be fired every time state changes irrespective of whether this check is needed or not.
Here's the link to the documentation.