Angular 带偏移分页的异步管道

Angular async pipe with offset pagination

我有一个 observable,它从目录中拉出 12 个人并显示到带有异步管道的模板上。它命中的 API 是相当基本的,只是使用偏移分页直接传递到 SQL 查询中来抓住人们。我希望我们在第一次加载时有 API returns 前 12 个人,然后我们有一个 'load more' 按钮。希望这个按钮可以让 12 个人保持在屏幕上,但通过更改偏移量再加载 12 个,所以第一次调用是偏移量 0,接下来是偏移量 11 等

我正在查看 forkJoin 或 shareReplay 之类的东西,因为我希望它具有反应性,并且还想避免向 API 询问越来越大的响应对象 - 加载更多的示例不想要求24 就在下一个 12

所以现在 onInit 我有第一个被拉进来的人

public people$: Observable<Directory[]> = combineLatest([this.selectedLocation$,this.selectedDepartment$, this.selectedSearchQuery$]).pipe(
switchMap(([loc,dept,query]) =>
  this.apiEmployeeService.getDirectory({
    dept: dept?.toString(),
    location: loc === 'Both' ? '%' : loc,
    offset: this.offset,
    limit: 12,
    search: query
  }),
)

所以我可以从 HTML 调用加载更多按钮来保留现有的 12 个人,然后重新启动这个可观察对象,但 offset 为 + 12

我们可以使用 BehaviorSubject 作为触发器来获取更多内容,并使用 scan 运算符将多次获取的结果累积到单个可观察对象中:

const ITEMS_PER_PAGE = 12;

export class AppComponent  {

  private fetch$ = new BehaviorSubject<void>(undefined);
  
  public people$: Observable<Employee[]> = combineLatest([
    this.selectedLocation$,
    this.selectedDepartment$, 
    this.selectedSearchQuery$,
  ]).pipe(
    switchMap(([loc, dept, search]) => this.fetch$.pipe(
      switchMap((_, pageIndex) => this.apiEmployeeService.getDirectory({
        dept     : dept?.toString(),
        location : loc === 'Both' ? '%' : loc,
        offset   : pageIndex * ITEMS_PER_PAGE,
        limit    : ITEMS_PER_PAGE,
        search
      })),
      scan((all, page) => all.concat(page), [])
    )),
  );

  fetchMore() {
    this.fetch$.next();
  }
}

嵌套 switchMap 的原因是因为我假设如果任何查询条件发生变化(location、dept、search),那么您想要offset 重置回 0。

switchMap 回调的第二个参数接收“排放指数”。我们可以用它来表示“页码”。每当 combineLatest 发出新值时,都会发生对 fetch$ 的新订阅,从而有效地重置索引。

这里有一些 StackBlitz,您可以在其中看到此行为的实际效果。