Reputation: 5
I try to carry out several requests and bring the respective results together.
I have a list of outfits which in turn can contain IDs of clothing items. When I call up the page, I try to get the clothes from a server using the ID. From this service I get an observable for every item of clothing.
How can I read out the data from these observables and merge them at the end?
To then output the merged data via a *ngfor
loop. If I try it as in the code below, the subscribe function takes longer until the data is there and everything else has already been carried out by then. So in the HTML file the data is undefined. I am sorry I hope I was able to clarify my problem.
PageComponent.ts
:
ngOnInit() {
this.isLoading = true;
this.outfitSub = this.outfitService.outfits.subscribe(outfits => {
this.geladeneOutfits = outfits;
});
}
ionViewWillEnter() {
this.isLoading = true;
this.outfitService.fetchOutfit().subscribe(() => {
this.geladeneOutfits.map(outfit => {
this.kleiderschrankService.getKleidungsstueck(outfit.oberteil1).subscribe(teil => {
this.oberteil1 = teil;
});
if(outfit.oberteil2 != null){
this.kleiderschrankService.getKleidungsstueck(outfit.oberteil2).subscribe(teil => {
this.oberteil2 = teil;
});
}
if(outfit.oberteil3 != null){
this.kleiderschrankService.getKleidungsstueck(outfit.oberteil3).subscribe(teil => {
this.oberteil3 = teil;
});
}
var outfitf = new OutfitKl (
this.oberteil1,
this.oberteil2,
this.oberteil3,
this.unterteil1,
this.unterteil2,
this.schuhe,
this.accessoir1,
this.accessoir2,
outfit.imageUrl
)
this.gezeigteOutfits.push(outfitf);
});
this.isLoading = false
});
}
PageComponent.html
:
<ion-grid *ngIf="!isLoading && gezeigteOutfits.length > 0">
<ion-row no-padding>
<ion-col>
<div>
<ion-card *ngFor="let outfit of gezeigteOutfits">
<img [src]="outfit.imageUrl" >
<ion-card-header>
<ion-card-subtitle>Kleidungsstuecke</ion-card-subtitle>
<ion-card-title>Oberteile</ion-card-title>
</ion-card-header>
<ion-card-content>
<ion-grid>
<ion-row no-padding>
<ion-col size="4" size-sm="3" offset-sm="2">
<div>
<ion-img [src]="outfit.oberteil1.imageUrl">
</ion-img>
<ion-img [src]="outfit.schuhe.imageUrl"></ion-img>
</div>
</ion-col>
</ion-row>
</ion-grid>
</ion-card-content>
</ion-card>
</div>
</ion-col>
</ion-row>
</ion-grid>
KleiderschrankService
:
getKleidungsstueck(kleidungsstueckId: string) {
const kleidungsstueckDocs = this.store
.collection("Kleidungsstueck")
.doc(kleidungsstueckId);
return kleidungsstueckDocs.snapshotChanges().pipe(
map((changes) => {
const data = changes.payload.data();
return data;
})
);
}
Upvotes: 0
Views: 492
Reputation: 1384
Use combineLatest from RxJS and use filter(), tap() to check for the data
combineLatest(
observable1,
observable2,
observable3
).pipe(
filter(data => !!data),
tap(data => console.log(data))
catchError(error => console.log(error))
).subscribe(
[dataFromObs1, dataFromObs2, dataFromObs33] => {
// This will subscribe only if all the observables return data
// Otherwise it will go to catchError
})
// Filter will check if the data is present or not.
// Tap will return the data before subscribing
// catchError ==> Subscription errors are caught in this catchError
Upvotes: 0
Reputation: 187
I tried to provide exact solution, however due to lack of information, this is the most:
ngOnInit() {
this.outfitSub = combineLatest(this.outfitService.outfits, this.outfitService.fetchOutfit()).subscribe(
([geladeneOutfits]) => {
geladeneOutfits.forEach(outfit => {
const subOb = [this.kleiderschrankService.getKleidungsstueck(outfit.oberteil1)];
outfit.oberteil2 && subOb.push(this.kleiderschrankService.getKleidungsstueck(outfit.oberteil2));
outfit.oberteil3 && subOb.push(this.kleiderschrankService.getKleidungsstueck(outfit.oberteil3));
(combineLatest.apply(this, subOb) as Observable<[any, any, any]>)
.subscribe(([ret1, ret2, ret3]) => {})
})
}
);
}
Upvotes: 0
Reputation: 309
combineLatest from RxJS should do the trick.
You can use something like this:
const first$ = this.kleiderschrankService.getKleidungsstueck(outfit.oberteil1);
const second$ = this.kleiderschrankService.getKleidungsstueck(outfit.oberteil2);
const third$ = this.kleiderschrankService.getKleidungsstueck(outfit.oberteil3);
combineLatest(first$, second$, third$).subscribe(([v1, v2, v3]) => {
//call the this.gezeigteOutfits.push(...) part here so it executes after the data has been recieved
});
Upvotes: 1