如何解决Angular Material后端分页时上/下页按钮禁用问题
我正在测试Angular Material分页功能,采用后端分页模式,即每次请求对应页码的指定数量数据。例如总共有7条记录,第一页请求5条数据,加载显示正常;切换到第二页时加载剩余2条,但此时分页组件的上一页和下一页按钮被禁用。我检查了pageIndex、pageSize参数均正常,而一次性加载全部数据时分页功能可正常工作。
模板代码
<div class="mat-elevation-z8"> <table mat-table [dataSource]="dataSource" matSort> <ng-container matColumnDef="photoPath"> <th mat-header-cell *matHeaderCellDef> Photo </th> <td mat-cell *matCellDef="let element"> <img [src]="element.photoPath" alt="Photo" width="50"> </td> </ng-container> <ng-container matColumnDef="fullName"> <th mat-header-cell *matHeaderCellDef mat-sort-header> Full Name </th> <td mat-cell *matCellDef="let element"> {{element.fullName}} </td> </ng-container> <ng-container matColumnDef="email"> <th mat-header-cell *matHeaderCellDef mat-sort-header> Email </th> <td mat-cell *matCellDef="let element"> {{element.email}} </td> </ng-container> <ng-container matColumnDef="dateOfBirth"> <th mat-header-cell *matHeaderCellDef mat-sort-header> DateOfBirth </th> <td mat-cell *matCellDef="let element"> {{element.dateOfBirth | date}} </td> </ng-container> <ng-container matColumnDef="mobile"> <th mat-header-cell *matHeaderCellDef mat-sort-header> Mobile </th> <td mat-cell *matCellDef="let element"> {{element.mobile}} </td> </ng-container> <ng-container matColumnDef="action"> <th mat-header-cell *matHeaderCellDef> Action </th> <td mat-cell *matCellDef="let element"> <button mat-button color="primary" (click)="editEmployee(element.id)">Edit</button> <button mat-button color="warn" (click)="deleteEmployee(element.id)">Delete</button> </td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table> <mat-paginator [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons [length]="totalRecords" [pageSize]="searchValues.pageSize"> </mat-paginator> </div>
组件类代码
export class DataTableComponent{ totalRecords: number = 100; // Declare totalRecords here displayedColumns: string[] = ['photoPath','fullName', 'email', 'mobile','dateOfBirth','action']; Employee!: Employee[]; dataSource = new MatTableDataSource<Employee>(this.Employee); @ViewChild(MatPaginator) paginator!: MatPaginator; @ViewChild(MatSort) sort!: MatSort; http = inject(HttpServiceService); router = inject(Router); dialog = inject(MatDialog); ngAfterViewInit() { // Now, the paginator is initialized, so we can safely load employees this.dataSource.paginator = this.paginator; this.dataSource.sort = this.sort; this.LoadEmployee(this.paginator.pageSize, this.paginator.pageIndex); this.paginator.page.subscribe((event: PageEvent) => { this.LoadEmployee(event.pageSize, event.pageIndex); }); } LoadEmployee(pageSize: number, pageIndex: number) { this.http.GetAllEmployee(pageSize, pageIndex + 1).subscribe((response: any) => { this.dataSource.data = response.data.items; this.paginator.length = response.data.total; // Set total number of records for paginator this.totalRecords = response.data.total; // Update totalRecords here this.paginator.pageSize = pageSize; console.log(this.paginator.pageSize, this.paginator.pageIndex, this.totalRecords) }); } }
问题原因及修复方案
1. 分页器长度绑定冲突
模板中mat-paginator已绑定[length]="totalRecords",但组件内又手动设置this.paginator.length = response.data.total,导致双向绑定冲突,分页器无法正确计算页码状态。
修复:移除组件内手动设置this.paginator.length的代码,仅通过totalRecords变量更新总条数。
2. PageSize绑定不一致
模板中mat-paginator绑定的是searchValues.pageSize,但组件初始化和请求时使用paginator.pageSize,还手动设置this.paginator.pageSize = pageSize,导致绑定值与控件实际值不匹配。
修复:统一使用组件内变量管理pageSize,替换模板中的searchValues.pageSize为组件内定义的pageSize变量。
3. 手动绑定paginator到DataSource
后端分页模式下,MatTableDataSource不需要绑定paginator,否则会触发自动分页逻辑,与手动分页冲突。
修复:移除this.dataSource.paginator = this.paginator代码。
修复后的完整代码
组件类代码
export class DataTableComponent{ totalRecords: number = 0; pageSize: number = 5; // 统一管理pageSize displayedColumns: string[] = ['photoPath','fullName', 'email', 'mobile','dateOfBirth','action']; Employee!: Employee[]; dataSource = new MatTableDataSource<Employee>(this.Employee); @ViewChild(MatPaginator) paginator!: MatPaginator; @ViewChild(MatSort) sort!: MatSort; http = inject(HttpServiceService); router = inject(Router); dialog = inject(MatDialog); ngAfterViewInit() { this.dataSource.sort = this.sort; // 初始化加载数据 this.LoadEmployee(this.pageSize, 0); // 监听分页事件 this.paginator.page.subscribe((event: PageEvent) => { this.pageSize = event.pageSize; this.LoadEmployee(event.pageSize, event.pageIndex); }); } LoadEmployee(pageSize: number, pageIndex: number) { this.http.GetAllEmployee(pageSize, pageIndex + 1).subscribe((response: any) => { this.dataSource.data = response.data.items; this.totalRecords = response.data.total; // 仅更新绑定的totalRecords // 确保分页器页码同步 if (this.paginator.pageIndex !== pageIndex) { this.paginator.pageIndex = pageIndex; } console.log(this.pageSize, this.paginator.pageIndex, this.totalRecords) }); } }
模板代码
<div class="mat-elevation-z8"> <table mat-table [dataSource]="dataSource" matSort> <ng-container matColumnDef="photoPath"> <th mat-header-cell *matHeaderCellDef> Photo </th> <td mat-cell *matCellDef="let element"> <img [src]="element.photoPath" alt="Photo" width="50"> </td> </ng-container> <ng-container matColumnDef="fullName"> <th mat-header-cell *matHeaderCellDef mat-sort-header> Full Name </th> <td mat-cell *matCellDef="let element"> {{element.fullName}} </td> </ng-container> <ng-container matColumnDef="email"> <th mat-header-cell *matHeaderCellDef mat-sort-header> Email </th> <td mat-cell *matCellDef="let element"> {{element.email}} </td> </ng-container> <ng-container matColumnDef="dateOfBirth"> <th mat-header-cell *matHeaderCellDef mat-sort-header> DateOfBirth </th> <td mat-cell *matCellDef="let element"> {{element.dateOfBirth | date}} </td> </ng-container> <ng-container matColumnDef="mobile"> <th mat-header-cell *matHeaderCellDef mat-sort-header> Mobile </th> <td mat-cell *matCellDef="let element"> {{element.mobile}} </td> </ng-container> <ng-container matColumnDef="action"> <th mat-header-cell *matHeaderCellDef> Action </th> <td mat-cell *matCellDef="let element"> <button mat-button color="primary" (click)="editEmployee(element.id)">Edit</button> <button mat-button color="warn" (click)="deleteEmployee(element.id)">Delete</button> </td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table> <mat-paginator [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons [length]="totalRecords" [pageSize]="pageSize"> </mat-paginator> </div>
内容的提问来源于stack exchange,提问作者SAFIQUL ISLAM UZZAL 203-15-144

