To make things easier to illustrate, I have a combined Observable combinedNotifications$ that I bind to the async pipe. It works nice and well for the first load. HOWEVER. I would like to be able to update notifications$ ONLY as well manually. So far, I never delved too much into observables as the use-cases were even simpler than this one so far.
combinedNotifications$: Observable<any> = combineLatest([
this.notifications$,
this.notificationTypes$
]).pipe(
map((i: any) => ({
tableData: i[0],
notificationTypes: i[1]
})),
map((f: any) => {
return ({
tableData: {
...f.tableData, content: f.tableData.content.map((v: any) => ({
...v,
type: f.notificationTypes.eventTypes.find((x: any) => x.value === v.type)?.label,
cause: f.notificationTypes.causeTypes.find((x: any) => x.value === v.cause)?.label
}))
},
notificationTypes: f.notificationTypes
})
}),
tap((d) => console.log(d)),
shareReplay(1)
);
I have a table that I interact with via pagination. Before I created this combined observable, I used to be able to update just the notifications:
retrieveNotificationsPage(queryArgs: Pageable = {}, searchData: any = {}) {
this._loading$.next(true);
const actionAuditLogsPage$ = this.apiService
.retrieveNotificationsView$(queryArgs, { ...searchData })
.pipe(
delay(300),
tap({
complete: () => {
this._loading$.next(false);
},
error: (err) => {
this._loading$.next(false);
throw err;
}
}),
catchError((err) => of({ error: err })),
// shareReplay()
);
return actionAuditLogsPage$;
}
Which then got called somewhat like this...
loadRecords(event: LazyLoadEvent) {
...
this.notifications$ = this.retrieveNotificationsPage({
page: isNaN(selectedPage) ? 0 : selectedPage,
...(maxPageRowSize != null ? { size: maxPageRowSize } : {})
}, this.searchForm.value);
}
So I thought I could probably do it with merge, but it only seems to be stuck in an infinite loop...
this.combinedNotifications$ = merge(notificationPage$, this.combinedNotifications$);
If I understand correctly, you want
notificationTypesandnotificationsto be loaded once on subscribe (viaasyncpipe) and then continue loadingnotificationson demand.There are a few ways to do this that differ in detail, here is an example how this can be done:
The key thing is using a
Subject, in my case I usedBehaviorSubjectbecause I can put an initial value there. And it is aSubjectthat emits observables, that then are unwrapped withswitchMap(identity)and make the actual calls.Alternatively, the
Subjectmay emit objects representing parameters for the API calls, so that then they can be transformed asswitchMap(params => makeACall(...params)).Here is a playground with the code from above.