Angular MatPaginator无法正常工作

Nag*_*rma 33 pagination angular-material angular

我有2个组件.两者都有mat-table和paginator,并且分页对一个组件起作用,而不是为另一个组件工作,尽管代码类似.下面是我的html:

<div class="mat-elevation-z8">

    <mat-table [dataSource]="dataSource" matSort>

      <ng-container matColumnDef="col1">
        <mat-header-cell *matHeaderCellDef mat-sort-header> Column1 </mat-header-cell>
        <mat-cell *matCellDef="let row"> {{row.col1}} </mat-cell>
      </ng-container>

      <ng-container matColumnDef="col2">
        <mat-header-cell *matHeaderCellDef mat-sort-header> Column2 </mat-header-cell>
        <mat-cell *matCellDef="let row"> {{row.col2}} </mat-cell>
      </ng-container>

      <!-- Different columns goes here -->

      <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
      <mat-row *matRowDef="let row; columns: displayedColumns;">
      </mat-row>
    </mat-table>

    <mat-paginator #scheduledOrdersPaginator [pageSizeOptions]="[5, 10, 20]"></mat-paginator>
  </div>
Run Code Online (Sandbox Code Playgroud)

以下是我在component.ts中的代码:

dataSource: MatTableDataSource<any>;
displayedColumns = ['col1', 'col2', ... ];
@ViewChild('scheduledOrdersPaginator') paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
ngOnInit(): void {
    // Load data
    this.dataSource = new MatTableDataSource(somearray);
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;
}
Run Code Online (Sandbox Code Playgroud)

类似的代码正在为其他组件工作,并且正确地使用分页呈现表,不知道此代码有什么问题.

任何帮助将非常感激

小智 49

我通过使用超时来围绕实例化解决了类似的问题.试试这个 :

setTimeout(() => this.dataSource.paginator = this.paginator);
Run Code Online (Sandbox Code Playgroud)

  • 这并不是真正的解决方案,而是一种 hack。任何使用此作为解决方案的人都是在冒险并且做错了。 (9认同)
  • 不是在刷新数据源时. (7认同)
  • angular为此提供了ngAfterViewInit` (6认同)
  • 不是解决方案,而是解决方法,请牢记这一点 (4认同)
  • 您可以将其替换为 [hidden]="!condition",而不是删除 *ngIf="condition",就像 Angular 将捕获并启动分页器和排序元素一样 (4认同)
  • 它做到了:) 疯了!!谢谢@trichetrice,但我可以知道为什么这种奇怪的行为 (2认同)

小智 44

在我的例子中,<mat-paginator>元素位于一个容器*ngIf上,该容器上有一个容器,在异步加载数据之前它不会呈现.这将导致this.paginatorundefined即使在ngAfterViewInit.这会导致它静默失败,因为MatTableDataSource您设置paginator为没有问题undefined.

解决方案是移动'd容器的<mat-paginator>外部*ngIf

希望这能帮助那些与我情况相同的人.

  • 谢谢-这是我的解决方案。我选择使用`[hidden]`而不是ngIf,这样即使没有任何数据,分页器也可以呈现,但不会向用户显示 (6认同)

hop*_*sey 18

虽然选择的答案有效并解决了问题,但它仍然是一种解决方法.这是处理问题的正确和更优雅的方式.

尝试向AfterViewInit您的类添加接口,然后放入this.dataSource.paginator = this.paginatorinside ngAfterViewInit()方法

    ngAfterViewInit() {
        this.dataSource.paginator = this.paginator
    }
Run Code Online (Sandbox Code Playgroud)

那么你就不必打电话给你setTimeout.

  • 这是更合适的方法 (3认同)
  • 这对我不起作用。我的数据源是在ngAfterViewInit之后加载的,这可能是问题所在。我尝试先初始化数据源,然后使用ngAfterViewInit设置分页器,但它不起作用。我发现唯一起作用的是已接受答案中的解决方法。 (2认同)

Muh*_*lal 18

第一个解决方案

将 mat-paginator 从 *ngIf div 内部移动到外部

第二种解决方案

在声明 MatPaginator 或 MatSort 时使用静态 false

@ViewChild(MatPaginator, {static: false}) paginator: MatPaginator;
@ViewChild(MatSort, {static: false}) sort: MatSort;
Run Code Online (Sandbox Code Playgroud)


小智 15

这是因为 this.paginator 在分配给 this.dataSource.paginator 时是未定义的。

如果您使用静态数据,这将起作用

 @ViewChild(MatPaginator, {static: false}) paginator: MatPaginator; // For pagination
 @ViewChild(MatSort, {static: false}) sort: MatSort; // For Sort

 ngOnInit(): void {
   this.dataSource.data = this.dataList; // Data list is data array 
 }

 ngAfterViewInit(): void {
   this.dataSource.paginator = this.paginator; // For pagination
   this.dataSource.sort = this.sort; // For sort
 }
Run Code Online (Sandbox Code Playgroud)

如果您使用动态数据(来自 API 的数据),这将起作用

用于分页

  @ViewChild(MatPaginator, {static: false})
  set paginator(value: MatPaginator) {
    if (this.dataSource){
      this.dataSource.paginator = value;
    }
  }
Run Code Online (Sandbox Code Playgroud)

对于排序

  @ViewChild(MatSort, {static: false})
  set sort(value: MatSort) {
    if (this.dataSource){
      this.dataSource.sort = value;
    }
  }
Run Code Online (Sandbox Code Playgroud)

作为旁注,我在运动中使用了 Angular 9。


Lon*_*ely 6

设置数据源后,立即调用ChangeDetectorRef.detectChanges():

// First import ChangeDetectorRef & Material related stuff
import { ..., ChangeDetectorRef } from '@angular/core';
import { MatSort, MatTableDataSource, MatPaginator } from '@angular/material';

// Set properties in your component
@ViewChild(MatSort) sort: MatSort;
@ViewChild(MatPaginator) paginator: MatPaginator;

// Inject in constructor
constructor (..., private cdr: ChangeDetectorRef, ...) { ... }

// Set data source and invoke detectChanges()
this.dataSource = new MatTableDataSource (MY_DATA);
this.cdr.detectChanges();

// after that you can set other properties like
this.dataSource.sort = this.sort;
this.dataSource.paginator = this.paginator;
Run Code Online (Sandbox Code Playgroud)

  • 当 mat-table 被 ng-if 包围时,在 Angular 9.1.2 中完美运行 (3认同)
  • 这非常有效。一个非常烦人的问题的好简单的解决方案。 (2认同)

Big*_*yes 6

我花了几个小时才弄清楚。

关键是this.dataSource = new MatTableDataSource<MyInterface>(Object.values(data)); 然后设置this.dataSource.paginator = this.paginator;

我正在使用this.dataSource = data虽然我可以获取数据但分页不起作用。

再次你必须使用new MatTableDataSource

适用于 Angular 11。


小智 5

为了使其工作,我必须在从源中获取数据后设置分页器

getVariables() {
    this.activeRoute.params.subscribe(params => {
        if (params['id'] && (params['type'] === Type.CodeList)) {
            this.dataService
                .getItems(this.currentLanguage, params['id'])
                .subscribe((items: any) => {
                    this.dataSource.data = this.items;
                    this.dataSource.paginator = this.paginator;
                })
        }
    })
}
Run Code Online (Sandbox Code Playgroud)


Gus*_*uss 5

分页器何时在视图中可用以及何时可以检索并附加到数据源的问题是这个问题的主要症结和常见的陷阱。此处建议的变通方法包括使用setTimeout()and ngAfterViewInit,就是这样的变通方法,即“让我们看看我们需要等待多少时间才能确保@ViewChild使用正确的分页器值设置我们的组件字段”。

正确的方法是将 附加@ViewChild到属性设置器并在使用有效分页器调用该设置器时尽快(并且经常)设置数据源分页器。

拥有单个数据源而不是每次加载都替换它也非常有用(正如我看到很多人所做的那样) - 只需将数据源绑定到 mat-table 并更新它的data字段。

 <mat-table [dataSource]="dataSource" matSort>

      <ng-container matColumnDef="col1">
        <mat-header-cell *matHeaderCellDef mat-sort-header> Column1 </mat-header-cell>
        <mat-cell *matCellDef="let row"> {{row.col1}} </mat-cell>
      </ng-container>

      <ng-container matColumnDef="col2">
        <mat-header-cell *matHeaderCellDef mat-sort-header> Column2 </mat-header-cell>
        <mat-cell *matCellDef="let row"> {{row.col2}} </mat-cell>
      </ng-container>

      <!-- Different columns goes here -->

      <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
      <mat-row *matRowDef="let row; columns: displayedColumns;">
      </mat-row>
    </mat-table>

    <mat-paginator #scheduledOrdersPaginator [pageSizeOptions]="[5, 10, 20]"></mat-paginator>
  </div>
Run Code Online (Sandbox Code Playgroud)
dataSource: MatTableDataSource<any> = new MatTableDataSource();
displayedColumns = ['col1', 'col2', ... ];

@ViewChild('scheduledOrdersPaginator') set paginator(pager:MatPaginator) {
  if (pager) this.dataSource.paginator = pager;
}

@ViewChild(MatSort) set sort(sorter:MatSort) {
  if (sorter) this.dataSource.sort = sorter;
}

ngOnInit(): void {
    this.loadData().subscribe(somearray => { this.dataSource.data = somearray; });
}
Run Code Online (Sandbox Code Playgroud)

这种方法还应该解决分页器隐藏在*ngIf模板后面时延迟呈现的问题(此处的一位评论者指出)- 即使分页器呈现得很晚,它也会被发送到数据源。