bugfix> angular > 投稿

私は配列を持っているので、配列をループして各項目のサーバーデータを呼び出します。ページをロードするときにAPIが保留状態になっているので、スピナーを表示したいと思います。

現在のソリューション:

 getRecordings(classroom) {
    return this.sysAdminService.getMeetingRecordings(classroom.meeting_id).subscribe(res => {
      classroom.recordings = res;
    });
  }

API呼び出し:

this.classRoomsToDisplay.map((classroom) => {
      classroom.showAttendees = false;
      classroom.recordings = null;
      this.getRecordings(classroom);
    });

上記のように、配列内の各項目のオブザーバブルをサブスクライブしています。rxjs、concatMapを使用してこれを行うより良い方法があるかどうかを知りたいですか?配列全体のAPI呼び出しが完了するのを待ちたくありません。その項目のAPI呼び出しが完了するとすぐに結果を表示します。

回答 2 件
  • 表示したデータから、データの表示に使用しているプロパティが明確ではありません。それだと思います classroom.showAttendees ブール値なので。

    あなたはRxJSを使うことができます forkJoin 複数のオブザーバブルを組み合わせて、複数のサブスクリプションを持つ代わりに1回サブスクライブする関数。そして、あなたは切り替えることができます showAttendees を使用して副作用として配列内の各項目のフラグ tap オペレーター。

    以下をお試しください

    complete$ = new Subject<any>();
    getRecordings(classroom): Observable<any> {   // <-- return the HTTP request observable
      return this.sysAdminService.getMeetingRecordings(classroom.meeting_id).pipe(
        tap => {
          classroom.showAttendees = true;         // <-- set the flag to show data
          classroom.recordings = res;
        }
      );
    }
    ngOnInit() {
      // `reqs` is an array of observables `[getRecordings(classroom), getRecordings(classroom), ...]`
      const reqs = this.classRoomsToDisplay.map((classroom) => {
        classroom.showAttendees = false;
        classroom.recordings = null;
        return this.getRecordings(classroom);
      });
      forkJoin(reqs).pipe(takeUntil(this.complete$)).subscribe();   // <-- trigger the HTTP requests
    }
    ngOnDestroy() {
      this.complete$.next();        // <-- close open subscriptions
    }
    
    

    テンプレート

    <div *ngFor="classroom of classRoomsToDisplay">
      <ng-container *ngIf="classroom.showAttendees">
        {{ classroom.recordings }}
      </ng-container>
    </div>
    
    

    ここで、 tap オペレーター、各アイテムのデータが到着するとすぐに表示されます。

  • サブスクリプションの代わりに非同期パイプを使用することをお勧めします。

    例:

    <ul>
      <li *ngFor="let attendee of attendeesWithData">Attendee: {{ attendee.attendee }}, duplicated: {{ (attendee.duplication | async) || 'pending' }}</li>
    </ul>
    
    

    この例では、非同期操作は文字列の複製であり、要求はデモンストレーションのために毎回より長くかかります。

    @Injectable()
    export class DuplicateService {
      times = 1;
      constructor() { }
      getDuplicated(s: string): Observable<string> {
        return timer(1000 * this.times++).pipe(
          map(() => s + s),
        );
      }
    }
    
    
    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: [ './app.component.css' ]
    })
    export class AppComponent  {
      private attendees: string[] = ['A', 'B', 'C', 'D', 'E', 'F'];
      attendeesWithData = this.attendees.map(attendee => ({ 
        attendee,
        duplication: this.duplicateService.getDuplicated(attendee),
      }));
      constructor(private duplicateService: DuplicateService) {}
    }
    
    

    その結果、1秒ごとに1つのリストアイテムの状態が保留中から複製された文字列に切り替わります。

    stackblitzも参照してください:https://stackblitz.com/edit/angular-ivy-rtx6cg?file=src/app/app.component.ts

あなたの答え