简体   繁体   中英

How to avoid multiple observable requests to the backend when using async pipe in template

I am trying to return individual Arrays to each entry in mat-option-select conditional to some conditions. However when i use getFoos(rowIndex, matSelectIndex) | async. It cause multi request to the backend. Here is my call stack,

**In HTML Template: **

<mat-option *ngFor="let foo of getFoos(rowIndex, matSelectIndex) | async"
                                [ngClass]="{'inactiveFoo': !foo?.status}"
                                [value]="foo.id">
                      <span [innerText]="foo.name"></span>
                    </mat-option>

The method getFoos in my ts file:



private obsFoos: BehaviorSubject<Foo[]> = new BehaviorSubject<Foo[]>([]);
private Foos$: Observable<Foo[]> = this.obsFoos.asObservable();

public getFoos(rowIndex: number, selectionIndex: number): Observable<Foo[]> {
    const someId: string = this.getId(rowIndex, selectionIndex);
    
    if(this.Foos$ && someId) {
      return this.Foos$.pipe(switchMap((foos) => {
        const missedFoo$: Observable<Foo[]> =      this._ksFoosService.getById(someId).pipe(
          tap((res) => this.obsFoos.next([...foos, res])),
          map(() => foos),
        );
        return iif(() =>
          someId && !foos.some(x => x.id === someId),
          missedFoo$,
          this.Foos$
        );
      }
      ))
    } else { return this.otherFoos$ }
  };

The problem is the getById will execute 20 times. Because this.obsFoos.next([...foos, res]) add the missing Foo later (when it get a response) and angular template keep calling the function.

What i did try is using shareReplay() and use some other rxjs methods to make the getById wait until it get a response. I also tried to avoid using iif().

I hope you could help guys.

Try to add shareReplay:

missedFoo$: Observable<Foo[]> =      this._ksFoosService.getById(someId).pipe(
          tap((res) => this.obsFoos.next([...foos, res])),
          map(() => foos),
    shareReplay(1)
    );

Using share() will allow you to share the results of an observable without triggering the observable chain more than once. It would look something like this:

missedFoo$: Observable<Foo[]> = this._ksFoosService.getById(someId).pipe(
  tap((res) => this.obsFoos.next([...foos, res])),
  map(() => foos),
  share()
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM