I'm facing an issue while using Angular Guards to fetch user information from an API. My goal is to always have up-to-date user data in local storage. I want to make sure the latest data is fetched from the API whenever there's a route change. To achieve this, I’ve been using guards to call the API and fetch the user information. However, the problem is that when the API is called within the guard, it causes a delay in opening the page (route), as the guard waits for the API response before proceeding. Because I created a function sequential guards which processes each guards sequentially instead of asynchronously, as you might see in the routes I have multiple guards for one route and I need the fresh data from user API before proceeding with the other routes. I don't really like this approach because it introduces unnecessary wait time in page navigation. So, I’m wondering if there's a better solution where the route can change without waiting for the API response, and the user data can be fetched asynchronously in the background but afterwards it shall pass the logic from the guards or kick him from the page - because the guards are there to protect the user from accessing pages based on his own properties, such as if the user is not onboarded he cannot access the /home page etc. sequentialGuards() export function sequentialGuards(guards: CanActivateFn[]): CanActivateFn { return (route, state) => { const injectionContext = inject(Injector); // Convert an array into an observable. return from(guards).pipe( // For each guard, fire canActivate and wait for it to complete. concatMap((guard) => { return runInInjectionContext(injectionContext, () => { var guardResult = guard(route, state); if (guardResult instanceof Observable) { return guardResult; } else if (guardResult instanceof Promise) { return from(guardResult); } else { return of(guardResult); } }); }), // Don't execute the next guard if the current guard's result is not true. takeWhile((value) => value === true, true), // Return the last guard's result. last() ); }; } routes { path: 'home', component: HomeComponent, canActivate: [sequentialGuards([authGuard, verifyGuard, onboardGuard])], }, { path: 'documents', component: DocumentsComponent, canActivate: [sequentialGuards([authGuard, verifyGuard, onboardGuard])], }, authGuard export const authGuard: CanActivateFn = (route, state) => { const url: string = decodeURIComponent(state.url); return inject(CheckLoginService).checkLogin(url); }; CheckLoginService export class CheckLoginService { constructor(private authService: AuthService, private tokenService: TokenService, private userService: UserService, private router: Router) { } checkLogin(url: string): Observable<boolean> { return this.authService.user().pipe( switchMap(() => { if (this.tokenService.getToken() && this.userService.getUser()) { return of(true); } this.authService.redirectUrl = url; this.router.navigate(['/login'], {queryParams: {returnUrl: url}}); return of(false); }), catchError(() => { this.authService.redirectUrl = url; this.router.navigate(['/login'], {queryParams: {returnUrl: url}}); return of(false); }) ); } } Continue reading...