I'm currently working on an infinite scroll data list where the data is loaded incrementally each time the host element is visible (invisible div at the end of each set of data).
I am however having trouble managing the subscriptions. I want to make the request and push more data into the array when the element is intersected.
I know nested subscriptions are an anti-pattern, so how can I get around this?
Here is the template and the logic:
<tbody>
<tr *ngFor='let movie of movieList; trackBy:trackByMovieId' (click)="selectMovie(movie.id)">
...
</tr>
<div *ngIf="!isOneFilterActive()" #sentinel> </div>
</tbody>
...
...
...
ngAfterViewInit(): void {
this.intersectionObserver.createAndObserve(this.sentinel).pipe(
filter((isVisible: boolean) => isVisible)).subscribe(() => {
// end of list detected: request more data
this.apiManager.fetchMovies().subscribe(movieList => {
if (movieList) {
this.movieList.push(...movieList.content);
}
});
}
);
}
CodePudding user response:
You can simply use a pipe operator to simplify the code like this
this.intersectionObserver.createAndObserve(this.sentinel)
.pipe(
filter((isVisible: boolean) => isVisible),
debounce(1000),
concatMap(x => this.apiManager.fetchMovies())
).subscribe(movieList => {
if (movieList) {
this.movieList.push(...movieList.content);
}
}
);
FLOW:
- A value from the intersection observer is fired
- Debounce operator will filter the value if the intersection observer is firing it rapidly ( Totally optional, remove this if it does not fit your use case)
- Concatmap operator returns a new observable of the movies to which you can subscribe now
NOTE: There is also switchMap and mergeMap the you can use that fit your use case
See: mergeMap