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