Reputation: 1104
My code looks like this:
userContext: UserContext;
userContext$ = this.http.get<UserContext>("assets/api/userContext.json", {}).pipe(
shareReplay(1),
tap((val: UserContext) => {
this.userContext = val;
console.log(this.userContext);
})
);
userAnnouncements$ = this.http.post<Announcement>(this.userAnnouncementsService,
{
countryCode: this.userContext.countryCode,
companyGroupId: this.userContext.companyGroupId,
}
);
As we can clearly see 2nd Service (userAnnouncements$) needs the values received by 1st service (userContext$), now since they are async my userContext: UserContext; is empty while the 2nd service is executed.
I would also need the userContext.companyCode & GroupId for future calls, hence I need a way to keep it somewhere for subsequent calls.
I tried resolver and APP_INT... but then realized this is not the right purpose of both places.
Upvotes: 0
Views: 185
Reputation: 1051
I was expecting your answer.
If you UserContext
is something it should be called once, as I mentioned, you can think of it as a singleton.
Fetch it once, then caches it inside your service.
class MyService {
private _userContext: UserContext | undefined;
constructor (private http: BackgroundService) { }
userContext$ = this.http.get<UserContext>(`url`).then(ctx => {
console.log(ctx);
this._userContext = ctx;
return ctx;
});
userAnnouncements$ = (): Promise<Announcement> =>
this._userContext
? this.userAnnouncement(this._userContext)
: this.userContext$.then(ctx => this.userAnnouncement(ctx));
private userAnnouncement = (ctx: UserContext): Promise<Announcement> =>
this.http.post<Announcement>(`url`, {
countryCode: ctx.countryCode,
companyGroupIp: ctx.companyGroupIp
});
}
interface BackgroundService { // aka HttpClient
get: <TResult>(url: string) => Promise<TResult>;
post: <TResult>(url: string, body: any) => Promise<TResult>;
}
I just mocked up the HttpClient
just for me to compile it properly. You can forget about it.
The point is, you service class has an inner property UserContext
. Any call to userContext$
will provide this object and caches inside the service.
If a call to userAnnouncements$
is done, then it uses the cached UserContext
. Whenever a call to userAnnouncements$
is done before any call to userContext$
, so UserContext
is null or undefined, then, a previous call to userContext$
is done to fulfill the property.
_userContext
may be static depending on your dependency injection policies. If you want to every service to store their own _userContext
, fine. Even if MyService
is singleton, then _userContext
should not be static. Otherwise, an static _userContext
is needed to share across all the service instances.
Moreover, you could overload the userAnnouncements$
to to force a UserContext
refetch. That would be interesting, if needed.
Hope it helps.
Upvotes: 1
Reputation: 12960
You already are using shareReplay
, only thing you have got to do is use the result of this Observable, wherever you want.
userAnnouncements$ = this.userContext$.pipe(mergeMap((userContextData) => {
return this.http.post<Announcement>('someUrl',
{
countryCode: userContextData.countryCode,
companyGroupId: userContextData.companyGroupId,
}
);
}));
Upvotes: 0
Reputation: 1956
Not sure if this is what you are asking for but you could use switchMap
userContext: UserContext;
userContext$ = this.http.get<UserContext>("assets/api/userContext.json", {}).pipe(
tap((val: UserContext) => {
this.userContext = val;
console.log(this.userContext);
}),
switchMap((val: UserContext) => {
return this.http.post<Announcement>(this.userAnnouncementsService,
{
countryCode: val.countryCode,
companyGroupId: val.companyGroupId
});
}
);
Then you only have one subscription
Upvotes: 0