1

I use new functional guards like:

export function AuthGuard() {
  const route = inject(ActivatedRoute);
  const authService = inject(AuthService);

  return authService.state$.subscribe((user) => {
    return user.uuid === route.snapshot.params.uuid;
  });
}

In the moment, current data of route.snapshot.params is empty. Subscription on Router events or ParamsMap does not give result.

Otherwise, when i use class-based guards with CanActivate, route data from ActivatedRouteSnapshot works perfectly, but authService get only first emit with undefined.

I figured out a workaround with placing combineLatest([route, authService]) with redirects in the Component, that need's this Guard.

I'm stuck. No way.

Solution: the main problem was in using BehaviorSubject in my authService, replacing to ReplaySubject solved first problem. Resolver usage solved the second part.

  • 1
    I don't think you have to subscribe inside the guard, just return the observable itself. Use pipe(tap(...)) instead to get your side effect. – Loop Feb 17 '23 at 13:47
  • @Loop - In functional guards it possible to use boolean return - Official Docs https://angular.io/guide/router-tutorial-toh#canactivate-requiring-authentication -> "src/app/auth/auth.guard.ts (v2)" code example. – Konstantin Grig Feb 20 '23 at 07:21
  • @Loop - Thank you for guiding me. I have read the documentation below more carefully and realized that it is need to use resolve - [link](https://angular.io/guide/router-tutorial-toh#resolve-pre-fetching-component-data) and get user auth state before guard – Konstantin Grig Feb 20 '23 at 07:30
  • 1
    Using subscribe you are not returning a boolean, you are returning an instance of subscription. If I had to guess, this would evaluate as truthy because its javascript and non null objects are evaluated as true. – Loop Feb 20 '23 at 21:42
  • @Loop - Thanks. You're definitely right. I checked and fixed it. – Konstantin Grig Feb 21 '23 at 13:01

1 Answers1

1

Actually you don't need to inject ActivatedRoute. If you want to read params from snapshot, your guard could look like this:

export function authGuard(snapshot: ActivatedRouteSnapshot) {
  const authService = inject(AuthService);

  return authService.state$.subscribe((user) => {
    return user.uuid === snapshot.params.uuid;
  });
}

Please note here, that I've added ActivatedRouteSnapshot as function param, instead of ActivatedRoute.
Now when you assign this function to canActivate in route definition just make sure you pass snapshot to this function:

{
  path: ':uuid',
  canActivate: [(snapshot: ActivatedRouteSnapshot) => authGuard(snapshot)],
},
rasiaq
  • 38
  • 5