Search code examples
angulartypescriptguard

Guard on children routes


I know the subject has often been treated on StackOverflow.

I consulted several posts on Stack but the suggested solution doesn't work for me.

For exemple this one

I try for the first time to restrict access to pages by using Guards but it doesn't work for child pages.

I have a Truck module containing childs like that :

Truck
  |_ truck-list
  |_ truck-search
  |_ truck-menu
  |_ truck-details

I have a route file for the Truck module :

RouterModule.forChild([
    {path: 'list', component: TruckListComponent, canActivate: [TruckGuard]},
    {path: 'search', component: TruckSearchComponent, canActivate: [TruckGuard]},
    {path: 'details/:id', component: TruckDetailsComponent},
    {path: 'menu', component: TruckMenuListComponent},
    {path: 'menu/:id', component: TruckMenuListComponent},
    {path: 'menu/add/:id', component: TruckMenuAddComponent},
    ])

and an app-routing module :

const appRoutes: Routes = [
    { path: '', component: HomeComponent},
    { path: 'app-forbidden', component: ForbiddenComponent},
    { path: 'Home', component: HomeComponent},
    { path: 'About', component: AboutComponent},
    { path: 'forbidden', component: ForbiddenComponent},
    { path: 'Login', component: LoginComponent},
    { path: 'Logout', component: LoginComponent},
    { path: 'confirmation-commande/:message', component: ConfirmationCommandeComponent},
    { path: 'orders', component: OrderListComponent},
    { path: 'truck/search', component: TruckSearchComponent},
    { path: 'SignUp/customer', component: UseraccountCreateCustomerComponent},
    { path: 'SignUp/truck', component: UseraccountCreateTruckComponent},
    { path: 'useraccount', loadChildren: () => import('./useraccount/useraccount.module').then(u => u.UserAccountModule)},
    { path: 'truck', loadChildren: () => import('./truck/truck.module').then(t => t.TruckModule)},
    {path: 'location', component: TruckLocationComponent},
    { path: '500', component: InternalServerComponent },
    { path: '', redirectTo: '/home', pathMatch: 'full' }
  ];
...

I also created a Truck.guard.ts file to manage route for the truck module :

export class TruckGuard implements CanActivate, CanActivateChild {

  constructor(private authService: AuthService, private route: Router) {}
  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    let url = window.location.pathname;

    if((url == '/truck') && this.authService.isCustomer()){
      return true;
    }
    else{
      this.route.navigate(['app-forbidden']);
      return false;
    }
  }
 
  canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    let url = window.location.pathname;

    if((url == '/truck/list') && this.authService.isCustomer()){
      return true;
    }
    else if((url == '/truck/search') && this.authService.isCustomer()){
      return true;
    }
    else if((url == '/Login') && this.authService.isCustomer()){
      return true;
    }
    else{
      this.route.navigate(['app-forbidden']);
      return false;
    }
  }
}

The only path that works is truck/list. He is well redirected to forbbiden page.

All the others doesn't work.

I don't understand why. Howver I use canActivate and canActivateChild.

Thanks in advence for your help.


Solution

  • Finaly the solution is to add canActivateChild in the app-module.ts:

     { path: 'truck', loadChildren: () => import('./truck/truck.module').then(t => t.TruckModule), canActivateChild: [TruckGuard]},
    

    and test url in the guard file using state: RouterStateSnapshot in place of window.location.pathname like this :

     if((state.url == '/truck/list') && this.authService.isCustomer()){
          return true;
        }
        else if((state.url == '/truck/search') && this.authService.isCustomer()){
          return true;
        }
       else if((state.url == '/truck/menu') && this.authService.isCustomer()){
          return true;
        }
        else if((state.url == '/truck/menu/' + childRoute.params['id']) && this.authService.isCustomer()){
          return true;
        }
        else if((state.url == '/truck/details/' + childRoute.params['id']) && this.authService.isCustomer()){
          return true;
        }
        else if((state.url == '/Login') && this.authService.isCustomer()){
          return true;
        }
        else{
          this.route.navigate(['app-forbidden']);
          return false;
        }