Brian Noyes Brian Noyes - 1 year ago 73
TypeScript Question

Pass parameter into route guard

I'm working on an app that has a lot of roles that I need to use guards to block nav to parts of the app based on those roles. I realize I can create individual guard classes for each role, but would rather have one class that I could somehow pass a parameter into. In other words I would like to be able to do something similar to this:

{
path: 'super-user-stuff',
component: SuperUserStuffComponent,
canActivate: [RoleGuard.forRole('superUser')]
}


But since all you pass is the type name of your guard, can't think of a way to do that. Should I just bit the bullet and write the individual guard classes per role and shatter my illusion of elegance in having a single parameterized type instead?

Answer Source

Try this,

app/service-factories/role-guard.ts

import UserService from 'app/services/user.services';

export default function roleGuard(...roles: string[]) {

  @injected class RoleGuard {
    constructor(readonly userService: UserService) { }

    async canActivate() {
      // hypothetical example
      const userRoles = await userService.getCurrentUserRoles();
      return userRoles.some(role => roles.includes(role));
    }
  }

  return RoleGuard;

  function injected(t: {}) { return t; } // POD (plain old decorator)
}

And use it like this

import roleGuard from 'app/service-factories/role-guard';
....
{
  path: 'super-user-stuff', 
  component: SuperUserStuffComponent,
  canActivate: [roleGuard('superUser')]
}

each time the function is invoked, it creates a brand new guard class for you. And the implementation of the guard class is trivial because it has direct access to the roles parameter simply because of lexical scoping.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download