schaenk
schaenk

Reputation: 682

Angular: Guard after resolved data

I'm having a route /invoices/:invoiceId for an invoice detail view which needs to be protected with 2 conditions

  1. User needs to be authenticated --> Redirect to login page
  2. Invoice with given id belongs to the logged in user --> Redirect to homepage with error message

My idea was to use a guard for authentication state - and since the view needs the invoice data - a resolver for loading the invoice.

But, what if the data can't be loaded from the resolver? E.g. server error, authenticated user not allowed to load the given invoice id, ... What's the best approach here?

Since guards are executed before any resolvers, i can't add another guard at the end.

Route

{
  path: 'invoice/:invoiceId',
  component: InvoiceComponent,
  canActivate: [authGuard],
  resolve: { invoice: invoiceResolver }
}

auth.guard.ts

export const authGuard: CanActivateFn = (_route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
  const authenticationPolicy = inject(AuthenticationPolicy);
  const router: Router = inject(Router);

  return authenticationPolicy.isGranted().pipe(
    catchError(() => {
      const queryParams = { referrer: state.url };
      const redirectUrl: UrlTree = router.createUrlTree(['login'], { queryParams });

      return of(redirectUrl);
    })
  );
};

invoice.resolver.ts

export const invoiceResolver: ResolveFn<Observable<Invoice | null>> = (route: ActivatedRouteSnapshot) => {
  const invoiceId = parseInt(route.paramMap.get('invoiceId') ?? '0', 10);

  const invoiceApiService = inject(InvoiceApiService);

  return invoiceApiService.invoice(invoiceId).pipe(catchError(() => of(null)));
};

Upvotes: 1

Views: 97

Answers (0)

Related Questions