Reputation: 3225
I have an AnuglarJS app using ui-router and i have a http request that tells information about the user such as login state, access, language, user group, what controllers he can access and so on. It also defines behavior for some controllers and my ui-router states rely on it.
$http.get("/user").then(function(response) {
UserService.userData = response.data.userData,
});
Now I would like to delay all of the ui-router state change AND delay Services to be loaded if possible. And only allow anything to happen in the angular app after the request returned. So I can either redirect the user to the login page or load the proper templates, or do whatever i want inside the application based on the information received.
I would like this to apply to multiple routes with possibly adding exceptions.
So the goal i would like to achieve is to delay the angular.js app being loaded, wait for the http request to finish then continue the application.
Upvotes: 0
Views: 937
Reputation: 18392
You could achieve this with $stateChangeStart
default event provided by ui-router
. It get called before any route change. You could put this stuff in the run()
part of your main application module define object.
/**
* Before state change / page switch
*/
$rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState, fromParams, options) {
//prevent default route change if user is not available in factory/service.
if ((!UserService.userData || !UserService.userData.loggedIn)
&& toState.name !== 'login') {
event.preventDefault();
$http.get("/user").then(function(response) {
if (response.data.loggedIn) {
UserService.userData = response.data.userData;
if (toState.name !== fromState.name) {
$state.go(toState.name, toParams, options);
}
} else {
$state.go('login');
}
});
}
});
Hint: It would be much better to not fire a HTTP-Request on any route-change just for checking the login session state. You could store the session state into localStorage which brings you performance push. Check this session state on any request which recives data from a secured route in your backend. If the session is not active any more, redirect the user in the moment he tries to access this data.
Upvotes: 1
Reputation: 4568
Whenever my app has dependencies on pre-loadeded data, be it user details, permissions, or whatever else, I nest all the apps routing under a single root route, and use the resolve
option for it.
For example, here is a piece of code that loads the user settings for locale, and then initializes my localization service that will go on to translate the entire app:
routeConfig.$inject = ['$stateProvider', '$urlRouterProvider'];
function routeConfig($stateProvider, $urlRouterProvider) {
$urlRouterProvider
.otherwise("/");
$stateProvider
.state('root', {
url: '',
abstract: true,
template: '<div navbar></div><div ui-view class="container"></div>',
resolve: {
dependencies: globalAppDependencies
}
})
.state('root.index', {
url: '/',
template: '<div main-page></div>'
})
.state('root.showcase', {
url: '/showcase',
template: '<div showcase-page></div>'
});
globalAppDependencies.$inject = ['userRepository', 'myLocalization'];
function globalAppDependencies(userRepository, myLocalization) {
return userRepository.login()
.then(function (user) {
return myLocalization.setLocale(user.locale);
});
}
}
Note: the root
route template holds a ui-view
, in addition to the one in the html template. This is required, since all the app views are nested below root
.
My app template looks like this:
<div ng-app="my-application">
<div application-loader></div>
<ui-view></ui-view>
</div>
The application-loader
is used for an animation while we're fetching the user settings and the localization files.
Upvotes: 1