Home > Software engineering >  How to avoid multiple observable requests to the backend when using async pipe in template
How to avoid multiple observable requests to the backend when using async pipe in template

Time:12-28

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.

CodePudding user response:

Try to add shareReplay:

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

CodePudding user response:

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()
);
  • Related