T
TanStack7mo ago
correct-apricot

Angular Tanstack Query

I am using Tanstack in my application and when a user logs in, I have a query that runs as part of the Auth to retrieve user profile info. I want to use the results of the query in a route guard to ensure users complete their profile before being able to access any other pages but I can't access anything from the query after injecting the AuthService because the query has not finished. Looking for some advice on how to achieve what I'm looking for.
3 Replies
other-emerald
other-emerald7mo ago
You probably want to use https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientfetchquery. Specifically queryClient.fetchQuery it returns a promise that you can await
correct-apricot
correct-apricotOP7mo ago
So in the auth service I use injectQuery to run the query based on a computed signal value. I have another signal for the results of the query (user profile info). When the guard runs, sometimes the user profile info is populated and at other times it is null - I guess it's a timing issue of whether the query is fetching or not. How can I make it so that the guard always has valid data. This is what I've implemented
const authService = inject(AuthService)
const router = inject(Router)
const currentUser$ = toObservable(authService.currentUser);

return currentUser$.pipe(
skipWhile(_ => authService.userQuery.isFetching()),
switchMap(user => {
if (user?.mobileNumber === null || user?.secondaryEmailAddress === null) {
return of(router.createUrlTree(["/", "teacher", "settings", "profile", { queryParams: { isEditMode: true }}]));
}
return of(true)
})
);
const authService = inject(AuthService)
const router = inject(Router)
const currentUser$ = toObservable(authService.currentUser);

return currentUser$.pipe(
skipWhile(_ => authService.userQuery.isFetching()),
switchMap(user => {
if (user?.mobileNumber === null || user?.secondaryEmailAddress === null) {
return of(router.createUrlTree(["/", "teacher", "settings", "profile", { queryParams: { isEditMode: true }}]));
}
return of(true)
})
);
which seems to do the trick.
vicious-gold
vicious-gold7mo ago
Using a promise based API as suggested by Sergey is probably best here. It's straightforward to use a promise in a route guard. Having loading state and such is great for UI but for a router guard doesn't help, nor does having a reactive query instance bound to an injection context. So just use functions on QueryClient itself such as fetchQuery or ensureQueryData that return a promise. If you want to integrate this into the service you could also add a method to it that returns a promise.

Did you find this page helpful?