I have 2 guards, AuthGuard and AccessGuard in the application. AuthGuard protects all the pages as the name suggests and stores the session object in the GlobalService and AccessGuard depends on the some access data in session object stored by AuthGuard in GlobalService.
Problem arises when AuthGuard returns an Observable and then simultaneously AccessGuard executes to check for session object which has not yet arrived and the code breaks. Is there any other way I can restrict the execution of AccessGuard until the session object arrives or any other work around to break this race condition?
#Note I have not merged the AccessGuard logic to AuthGuard as only some of the routes need to be checked for access while all other needs authentication. For example, Accounts page and DB page are accessible to all but User Managements and Dashboard need external access parameters that come from session object
export const routes: Routes = [
{
path: 'login',
loadChildren: 'app/login/login.module#LoginModule',
},
{
path: 'logout',
loadChildren: 'app/logout/logout.module#LogoutModule',
},
{
path: 'forget',
loadChildren: 'app/forget/forget.module#ForgetModule',
},{
path: 'reset',
loadChildren: 'app/reset/reset.module#ResetModule',
},
path: 'pages',
component: Pages,
children: [
{ path: '', redirectTo: 'db', pathMatch: 'full' },
{ path: 'db', loadChildren: 'app/pages/db/db.module#DbModule' },
{ path: 'bi', loadChildren: 'app/pages/dashboard/dashboard.module#DashboardModule', canActivate:[AccessableGuard] },
{ path: 'account', loadChildren: 'app/pages/account/account.module#AccountModule' },
{ path: 'um', loadChildren: 'app/pages/um/um.module#UserManagementModule', canActivate:[AccessableGuard] },
],
canActivate: [AuthGuard]
}
];
export const routing: ModuleWithProviders = RouterModule.forChild(routes);
#EDIT: Adding the Guard Codes
AuthGuard:
canActivate(route:ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean{
return new Observable<boolean>( observer => {
this._dataService.callRestful('POST', params.SERVER.AUTH_URL + urls.AUTH.GET_SESSION).subscribe(
(accessData) => {
if (accessData['successful']) {
observer.next(true);
observer.complete();
console.log("done");
}
else {
observer.next(false);
observer.complete();
}
});
});
}
AccessableGuard:
canActivate(route:ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean{
if(this._dataService.getModulePermission(route.routeConfig.path.toUpperCase()) < 2){
return false;
}
return true;
}
#NOTE: _dataService is GlobalService that stores the Access Permissions from AuthGuard.
Take a look at this Angular guide (link). "If you were using a real world API, there might be some delay before the data to display is returned from the server. You don't want to display a blank component while waiting for the data.
It's preferable to pre-fetch data from the server so it's ready the moment the route is activated. This also allows you to handle errors before routing to the component...
In summary, you want to delay rendering the routed component until all necessary data have been fetched.
You need a resolver."