Well here I am really bad with RxJs and I am facing a problem.
In one of my Angular component I load data like this:
this._obs$.push(this.store1.loadTypes());
this._obs$.push(this.store2.loadLimitQuantities());
// [...]
forkJoin(this._obs$).subscribe(
next => console.log(next),
error => console.log(error)
);
One of the observables receives data from API 1 and then needs to retrieve data from API 2 from the data received from API 1:
loadLimitQuantities(): Observable<LimitQuantity[]> {
// API 1
const obs = this.limitQuantityService.getLimitQuantities().pipe(share());
obs.subscribe(data => {
if (data) {
const ifs = [];
data.forEach(element => {
// API 2
ifs.push(this.technicalAttribTextIFSService.getType(element.ifsType).pipe(take(1), tap((type) => {
type ? element.type = type.valueText : element.type = null;
})));
});
forkJoin(ifs).subscribe(end => {
this.limitQuantitiesSubject.next(data);
});
} else {
console.error("Erreur lors du chargement des quantités limites");
}
});
// AP1
return obs;
}
Unfortunately the next
of my Angular component which loads the data is received too early because API 1 has finished returning the data but not API 2.
How to do ? The return
should be at the forkJoin
of API 2.
StackBlitz : here
Thanks for your help.
I'm not sure I got your problem 100% - but I think this will get you what you need.
limitedQuantitiesWithTypeFromApi2$ = this.loadLimitQuantities()
.pipe(
switchMap(
x => forkJoin(x.map(y => this.getType(y.ifsType))),
),
);
ngOnInit() {
forkJoin(this.loadTypes(), this.limitedQuantitiesWithTypeFromApi2$)
.subscribe(([types, lq]) => console.log('Original 1', types, lq));
forkJoin(this.loadTypes(), this.loadLimitQuantities())
.pipe(
map(([types, lq]) => {
return lq.map(x => ({
...x,
type: types.find(y => y.ifsType === x.ifsType)
}))
})
)
.subscribe(x => console.log('Alternate Approach', x));
}
loadTypes() {
return timer(1000).pipe(
map(x => ([
{ ifsType: 1, type: 'vText1'},
{ ifsType: 2, type: 'vText2'}
])),
share()
);
}
loadLimitQuantities() {
return timer(1000).pipe(
map(x => ([
{ifsType: 1, type: null, },
{ifsType: 2, type: null }
])),
share(),
);
}
getType(ifsType: number) {
return timer(1000).pipe(
map(x => ifsType === 1 ? 'vText1' : 'vText2'),
map(x => ({ ifsType, type: x })),
share()
);
}
However, I think it's safe to assume that your API2 is an HTTP call - and while it would work, I would advice to just batch fetch all the "type-associations" so you can just make a simpler stream.
I mean if loadTypes
already has an ifsType
to type
associaction then you can just do the "Approach 2" subscription - and if you're using angular anyway, you can just use the async
pipe to subscribe to loadTypes
and loadLimitedQuantities
.