You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular分页功能异常:加载后端数据后无法切换页面

Angular Material表格分页无法切换下页问题

我使用Angular Material的表格分页组件从后端拉取数据,基础配置如下:

dataSource = new MatTableDataSource<List_Product>;
@ViewChild(MatPaginator) paginator: MatPaginator;

this.dataSource = new MatTableDataSource<List_Product>(allProducts.products);
this.dataSource.paginator = this.paginator;

目前能正常加载产品列表,但设置每页显示5条时无法切换到下一页,求排查原因。以下是完整代码:

list.component.ts

export class ListComponent extends BaseComponent implements OnInit, AfterViewInit  {

  constructor(spiner: NgxSpinnerService, private productService: ProductService, private alertifyService: AlertifyService) {
    super(spiner)
  }

  displayedColumns: string[] = ['name', 'stock', 'price', 'createdDate', 'updatedDate'];
  dataSource = new MatTableDataSource<List_Product>;
  @ViewChild(MatPaginator) paginator: MatPaginator;

  async getProducts() {
    this.showSpinner(SpinnerType.SquareLoader);
    const allProducts: { totalProductCount: number; products: List_Product[] } = await this.productService.read(this.paginator ? this.paginator.pageIndex : 0, this.paginator ? this.paginator.pageSize : 5, () => this.hideSpinner(SpinnerType.BallSpinFadeRotating), errorMessage => this.alertifyService.message(errorMessage, {
      dismissOthers: true,
      messageType: MessageType.Error,
      position: Position.TopRight
    }))
    this.dataSource = new MatTableDataSource<List_Product>(allProducts.products);
    this.dataSource.paginator = this.paginator;
    console.log("paginator: " + this.dataSource.paginator.pageSize)
  }

  async pageChanged() {
    await this.getProducts();
  }

  async ngOnInit() {
    await this.getProducts();
  }
}

list.component.html

<div class="mat-elevation-z8">
  <table mat-table [dataSource]="dataSource">

    <ng-container matColumnDef="name">
      <th mat-header-cell *matHeaderCellDef> Name </th>
      <td mat-cell *matCellDef="let element"> {{element.name}} </td>
    </ng-container>

    <ng-container matColumnDef="stock">
      <th mat-header-cell *matHeaderCellDef> Stock </th>
      <td mat-cell *matCellDef="let element"> {{element.stock}} </td>
    </ng-container>

    <ng-container matColumnDef="price">
      <th mat-header-cell *matHeaderCellDef> Price </th>
      <td mat-cell *matCellDef="let element"> {{element.price}} </td>
    </ng-container>

    <ng-container matColumnDef="createdDate">
      <th mat-header-cell *matHeaderCellDef> Created Date </th>
      <td mat-cell *matCellDef="let element"> {{element.createdDate}} </td>
    </ng-container>

    <ng-container matColumnDef="updatedDate">
      <th mat-header-cell *matHeaderCellDef> Updated Date </th>
      <td mat-cell *matCellDef="let element"> {{element.updatedDate}} </td>
    </ng-container>

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

  <mat-paginator (page)="pageChanged()"
                 [pageSizeOptions]="[5, 10, 20]"
                 showFirstLastButtons
                 aria-label="Select page of periodic elements">
  </mat-paginator>
</div>

product.service.ts

async read(page: number = 0, size: number = 5, successCallBack?: () => void, errorCallBack?: (errorMessage: string) => void): Promise<{ totalProductCount: number; products: List_Product[] }> {
    const promiseData: Promise<{ totalProductCount: number; products: List_Product[] }> =  firstValueFrom(this.HttpClientService.get<{ totalProductCount: number; products: List_Product[] }>({
      controller: "products",
      queryString: `page=${page}&size=${size}`
    }));

    promiseData.then(d => successCallBack())
      .catch((errorResponse: HttpErrorResponse) => errorCallBack(errorResponse.message))

    return await promiseData;
  }

问题原因及修复方案

1. 未设置分页总条数

Angular Material分页组件需要知道总数据量才能正确计算页码范围和切换逻辑,当前仅传入了当前页数据,未告知分页器总产品数。

修复: 在getProducts方法中添加总条数绑定:

this.dataSource = new MatTableDataSource<List_Product>(allProducts.products);
this.dataSource.paginator = this.paginator;
this.paginator.length = allProducts.totalProductCount; // 新增此行

2. 重复创建MatTableDataSource实例

每次调用getProducts都重新创建dataSource,会导致分页器的状态绑定异常、状态丢失。应复用同一个实例,仅更新数据内容。

修复:

  • 初始化时创建一次实例:
    dataSource = new MatTableDataSource<List_Product>([]);
    
  • 在getProducts中替换数据创建逻辑:
    // 替换原两行创建代码
    this.dataSource.data = allProducts.products;
    

3. 分页器初始化时机问题

组件实现了AfterViewInit但未使用,@ViewChild获取的paginator在ngOnInit阶段可能未完成初始化,导致首次调用时参数获取异常。

修复:

  • 在ngAfterViewInit中完成分页器的首次绑定:
    ngAfterViewInit() {
      this.dataSource.paginator = this.paginator;
    }
    
  • 优化getProducts中的参数获取逻辑:
    const pageIndex = this.paginator?.pageIndex ?? 0;
    const pageSize = this.paginator?.pageSize ?? 5;
    const allProducts = await this.productService.read(pageIndex, pageSize, () => this.hideSpinner(SpinnerType.BallSpinFadeRotating), errorMessage => this.alertifyService.message(errorMessage, {
      dismissOthers: true,
      messageType: MessageType.Error,
      position: Position.TopRight
    }));
    

4. 分页事件参数优化

直接从分页事件中获取参数,避免依赖paginator实例的状态:

  • 修改模板中的事件绑定:
    <mat-paginator (page)="pageChanged($event)"
                   [pageSizeOptions]="[5, 10, 20]"
                   showFirstLastButtons
                   aria-label="Select page of periodic elements">
    </mat-paginator>
    
  • 修改pageChanged方法:
    async pageChanged(event: PageEvent) {
      this.showSpinner(SpinnerType.SquareLoader);
      const allProducts = await this.productService.read(event.pageIndex, event.pageSize, () => this.hideSpinner(SpinnerType.BallSpinFadeRotating), errorMessage => this.alertifyService.message(errorMessage, {
        dismissOthers: true,
        messageType: MessageType.Error,
        position: Position.TopRight
      }));
      this.dataSource.data = allProducts.products;
      this.paginator.length = allProducts.totalProductCount;
    }
    

内容的提问来源于stack exchange,提问作者Olcaytp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 18:34:58