Accessing component of the ActivatedRoute in the canActivate Guard
Asked Answered
C

1

7

As far as I know the call signature of canActivate looks like this:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {

}

I have a service that expects the name of a component and returns the necessary user role to access this component, so that I can check in the canActivate function of my guard, whether the active user has the corresponding role or not. My problem is, that I don't know how to access the component. After some googling I found solutions like this:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
  const nameOfComponent = route.routeConfig.component.name;
  return doSomeRoleCheck(nameOfComponent);
}

But in my case I just get an error: "Cannot read proprty 'name' of undefined". How can I access the component of the active Route or especially the name as a string?

Edit

I found out, that I do check this guard on a parent route. When I check it in the child route it works. How can I access the child component from parent can ActivatedRouteSnapshot

Childs answered 6/12, 2017 at 17:4 Comment(6)
with your current setup, you could probably expose a static member on the component class and access that directly as a list of accepted roles. If you're doing it generically, it would be best to have an interface to ensure that all routing components have that list.Greenlaw
Sounds interesting. Can you sketch up how this would be programmed?Childs
sure, I'll put it below.Greenlaw
Thanks. Now I understand what you mean. Another question: I have a parent route "" which guards all child routes. As the parent route has no related component, it throws "Cannot read property 'name' of undefined". How can I access the component of the child route?Childs
You could put the guard on each child route, or if every child route has the same role requirements for that parent, put the guard and the roles on the parent and give it a simple component to hook into.Greenlaw
yeah, that should workChilds
G
7

Something like this would probably work in your case:

export abstract class RoleCheck {
  myRoles: string[];
}

@Component({ ... })
export class YourComponent extends RoleCheck {
  public myRoles = ['User', 'Admin'];
}

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
  if (!route.routeConfig.component instanceof RoleCheck) {
    //Throw
  }
  return doSomeRoleCheck(route.routeConfig.component.myRoles)
}
Greenlaw answered 6/12, 2017 at 17:39 Comment(4)
How would I make that work with an interface given that my class already extends from another class. (an not wanting to create yet more specific extensions)Raffish
You could export another version that imports your existing version and extends it while implementing RoleCheck as an interface, then just export that version as default, or something similar.Greenlaw
routeConfig.component doesn't return a component instance, it doesn't seem like you should be able to access properties like this unless they were static?Surrebuttal
My comment was from 3 years ago, so the API may have changed. You are correct that if it's not a component instance the roles would need to be static, but I don't see why that wouldn't be fine here.Greenlaw

© 2022 - 2024 — McMap. All rights reserved.