2 相同数据源的 mat-paginator

2 mat-paginator for the same data source

我有一个 mat-table,每页最多可显示 100 个条目。起初,我在底部有一个 mat-paginator,效果很好。现在我被要求在 table 的顶部设置一个分页器,在 table 的底部设置另一个分页器,这样如果用户正在寻找一个位于顶部的条目。
问题是两个分页器必须链接到相同的数据源。 我尝试为每个人提供不同的 id,使用 ViewChild 获取它们并将它们分配给相同的数据源,但它只适用于其中一个。

main.component.ts:

    flights: Flight[] =[];
    dataSource = new MatTableDataSource<Flight>(this.flights);
    @ViewChild('PAGINATOR') paginator: MatPaginator;
    @ViewChild('OTROPAGINATOR') paginatorOtro: MatPaginator;

main.component.html:

   <mat-paginator #PAGINATOR (page)="pageEvent = handlePage($event)" 
   [length]="length" [pageSizeOptions]="[25, 50, 100]" showFirstLastButtons> 
   </mat-paginator>

   <table mat-table ...> ... </table>

  <mat-paginator #OTROPAGINATOR (page)="pageEvent = handlePage($event)" 
  [length]="length" [pageSizeOptions]="[25, 50, 100]" showFirstLastButtons> 
  </mat-paginator>

将分页器链接到数据源:

    this.dataSource = new MatTableDataSource<Flight>(this.flights);
    this.dataSource.paginator = this.paginator;
    this.dataSource.paginator = this.paginatorOtro;

有人可以指导我吗?

我找不到为同一数据源设置 2 个分页器的方法。我这样做的方法是使用数据源的副本设置第二个分页器,然后根据另一个分页器的更改移动每个分页器。

此外,我无法直接设置页面索引或每页项目属性(table 不刷新),因此所有移动都是通过一些逻辑和分页器方法实现的,如 previousPage() 或lastPage().

唯一的限制是底部的分页器无法更改每页的项目,因为没有一种方法可以让我控制 属性。

您可以看到关于使用 2 个数据源并同步两个分页器的解决方案的结果 here. Thanks FabianKüng

我希望这对某人有用。

dataSource = new MatTableDataSource;
@ViewChild('paginatorTop',{static:false}) topPaginator: MatPaginator;
@ViewChild('paginatorBottom',{static:false}) bottomPaginator: MatPaginator;
     
this.dataSource = new MatTableDataSource<any>(this.tableData);

设置api数据到数据源

非常感谢 Gustavo Alejandro 提供的解决方案。我将它用于我的 angular v11 项目。

一个简单的解决方案:

The only limitation is that the paginator at the bottom can't change items per page, since there isn't a method that lets me control that property.

是在 handlePageBottom() 方法内部需要使用新值为 topPaginator 发出事件:

handlePageTop(e): void {
    const {pageSize, pageIndex} = e;
    this.bottomPaginator.pageSize = pageSize;
    this.bottomPaginator.pageIndex = pageIndex;
  }

  handlePageBottom(e): void {
    const {pageSize, pageIndex} = e;
    this.topPaginator.pageSize = pageSize;
    this.topPaginator.pageIndex = pageIndex;
    this.topPaginator.page.emit(e);
  }

  ngAfterViewInit(): void {
    merge(
      this.topPaginator.page // we don't need both
    ).pipe(startWith({}),
      debounceTime(300)).subscribe() => {
       // do something
    });
  }
}

您不需要从 @angular/material/paginator 导入 PageEvent,因为您的模板将如下所示:

<mat-paginator #paginatorTop
               (page)="handlePageTop($event)" 
               [length]="resultsLength" 
               [pageSizeOptions]="[10, 25, 50, 100]" 
               [pageSize]="25">
</mat-paginator>

受@AlleXyS 回答的启发,我创建了完整的工作代码,通过使用相同的数据源在 material table 的顶部和底部完成垫分页器。尽管我不得不做出一些重大改变。重要的是将顶部分页器与 handlePaginatorBottom 方法连接起来,反之亦然。这样两者就保持同步。当在 handlePaginatorTop 中使用底部分页器时,将发出一个页面事件以触发分页器一的页面可观察到根据数据加载。

这里是完整的实现,因为它有点棘手。

模板实现:

<mat-paginator
    #paginatorTop
    (page)="handlePaginatorBottom($event)"
    [length]="resultsLength"
    [pageSize]="30"
  ></mat-paginator>
  
  <div class="table-container">
    <table
      mat-table
      [dataSource]="data"
      multiTemplateDataRows
    >
// ...
    </table>
 </div>
 <mat-paginator
      #paginatorBottom
      (page)="handlePaginatorTop($event)"
      [length]="resultsLength"
      [pageSize]="30"
    ></mat-paginator>

Class 实施:

// ...

@ViewChild('paginatorTop', { static: false })
paginatorTop: MatPaginator
@ViewChild('paginatorBottom', { static: false })
paginatorBottom: MatPaginator

// ...

ngAfterViewInit() {
        
        this.paginatorTop.page
            .pipe(
                startWith({}),
                switchMap(() => {
                    // ...
                    // use switch map to load data via another observable
                })
                map((data) => {
                    this.isLoadingResults = false
                    this.resultsLength = data.count
                    return data.items
                }),
                catchError(() => {
                    this.isLoadingResults = false
                    return of([])
                })
            )
            .subscribe((data) => {
                this.data = data
            })
    }

    handlePaginatorTop(e): void {
        const { pageSize, pageIndex } = e
        this.paginatorTop.pageSize = pageSize
        this.paginatorTop.pageIndex = pageIndex
        this.paginatorTop.page.emit(e)
    }

    handlePaginatorBottom(e): void {
        const { pageSize, pageIndex } = e
        this.paginatorBottom.pageSize = pageSize
        this.paginatorBottom.pageIndex = pageIndex
    }