Search code examples
angularangular-routingangular-router

Angular Inject() function doesn't provide router to CanActivateFn


I am trying to use one of the Angular v14 features which is CanActivateFn.

Unfortunately, when my guard is executed and the statement in return is false, I am not getting redirected. Error is being thrown:

Uncaught (in promise): TypeError: router.parseUrl is not a function TypeError: router.parseUrl is not a function

allowed-entities.guard.fn.ts

export function AllowedEntitiesGuard(allowedEntities: string[]): CanActivateFn {
  const router = Inject(Router);
  return (route: ActivatedRouteSnapshot) => {
    const entitiesTypeParameter = route.paramMap.get('entitiesType')

    return allowedEntities.indexOf(entitiesTypeParameter) !== -1 ? true : router.parseUrl('/');
  };
}

main.ts

bootstrapApplication(AppComponent, {
  providers: [
    provideHttpClient(withInterceptorsFromDi()),
    {
      provide: HTTP_INTERCEPTORS,
      useClass: JwtInterceptor,
      multi: true,
    },
    { provide: APP_CONFIG, useValue: environment },
    provideRouter(APP_ROUTES),
  ],
});

When I am trying to console.log router, it shows me its function ParamDecorator instance. What I am doing wrong?


Solution

  • The problem was related to wrong import.

    I should use inject instead of Inject.

    allowed-entities.guard.fn.ts

    // Good!
    import { inject } from '@angular/core';
    
    // Absolutely wrong!    
    import { Inject } from '@angular/core';
    

    Another thing. I cannot use inject() like above in the original post, because of NG0203. I had to move Router injection into CanActivateFn body, so it belongs to context.

    I ended up with guard looking like that:

    allowed-entities.guard.fn.ts

    export function AllowedEntitiesGuard(allowedEntities: string[]): CanActivateFn {
      return (route: ActivatedRouteSnapshot): boolean | UrlTree => {
        const router: Router = inject(Router);
        const entitiesType: string | null = route.paramMap.get(
          'entitiesType'
        );
    
        return allowedEntities.indexOf(entitiesType) !== -1 ? true : router.parseUrl('/');
      };
    }
    

    With this approach, I can pass the entities directly into the guard. No need to specify additional data parameter and then retrieve it from ActivatedRouteSnapshot.

    app.routes.ts

    canActivate: [AllowedEntitiesGuard(['EntityTypeOne', 'EntityTypeTwo'])