Angular:结合多个订阅

时间:2021-01-23 17:40:18

标签: html angular typescript

我尝试执行多个请求并将各自的结果汇总在一起。

我有一个服装列表,其中可以包含服装项目的 ID。当我调用页面时,我尝试使用 ID 从服务器获取衣服。通过这项服务,我获得了每件衣服的 observable。

如何从这些 observable 中读出数据并在最后合并它们?

然后通过 *ngfor 循环输出合并的数据。如果我在下面的代码中尝试它,订阅功能需要更长的时间,直到数据存在并且其他所有事情都已经执行完毕。所以在 HTML 文件中,数据是未定义的。对不起,我希望我能够澄清我的问题。

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;
    })
  );
}

3 个答案:

答案 0 :(得分:1)

来自 RxJS 的

combineLatest 应该可以解决问题。

你可以这样使用:

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
});

答案 1 :(得分:0)

我试图提供准确的解决方案,但由于缺乏信息,这是最多的:

 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]) => {})
        })
      }
    );
  }

答案 2 :(得分:0)

使用 RxJS 中的 combineLatest 并使用 filter()、tap() 检查数据

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