Reputation: 882
There is function, which loads user details. This function returns observable. It is called from multiple places. To avoid redundant calls I'd like to wait somehow after the first call until the result is loaded. Any idea haw this can be done using RxJs and Angular?
getUser(): Observable<any> {
return this.http.get('/userAuthenticated');
}
The idea is to wait somehow until the first call is completed and save result in the static variable:
getUser(): Observable<any> {
if(!this.userIsLoading) {
this.userIsLoading = true;
return this.http.get('/userAuthenticated').pipe(
tap((res: any) => {
this.userIsLoading = false;
this.User = res.data;
}));
} else {
// wait until the first call is completed
return of(this.User);
}
}
another idea is to define a static variable for the observable.
please help
Upvotes: 0
Views: 1039
Reputation: 6579
req$ = this.http.get('/userAuthenticated').pipe(shareReplay(1));
getUser(): Observable<any> {
return this.req$
}
You can use the shareReplay
operator to cache the result after the first (and then only) call to the backend. Any late
subscriber will get the cached result
You can read more about shareReplay here: https://rxjs.dev/api/operators/shareReplay
Upvotes: 1
Reputation: 6716
To achieve that, you can:
Observable
property under your service/component, with the shareReplay operator to avoid calling the API many times and share the result with each one of the new subscribers.Observable
from the getUser
function (You can't add the shareReplay
directly here, because every time the getUser
is called, it returns a new Observable
with shareReplay
, without returning the same one, which won't work in your case).Try something like the following:
// import { shareReplay } from 'rxjs/operators';
private userSource$ = this.http.get('/userAuthenticated').pipe(shareReplay());
getUser(): Observable<any> {
return this.userSource$;
}
Upvotes: 1
Reputation: 10994
Rxjs has the function firstValueFrom()
which returns a promise
that you can await
.
async getUser(): Promise<Observable<any>> {
if (!this.userIsLoading) {
this.userIsLoading = true;
return this.http.get('/userAuthenticated').pipe(
tap((res: any) => {
this.userIsLoading = false;
this.User = res.data;
})
);
} else {
await firstValueFrom(this.http.get('/userAuthenticated'));
return of(this.User);
}
}
Upvotes: 0