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

Angular10使用MatTable分页器出现多个Cannot read property 'length' of undefined错误如何解决

错误原因

你遇到的报错核心来自两个问题:

  1. 自定义DataSource的data属性没有初始化默认值,API异步请求返回数据前data为undefined,此时模板、组件逻辑里访问data.length就会抛出空指针错误。
  2. 数据流设计不合理:connect方法中使用observableOf(this.data)只能传递初始的静态值,API返回新数据后无法触发表格的更新流,即使数据赋值成功也不会主动触发重渲染(虽然你现在能看到数据可能是其他巧合触发了变更检测,但这是不稳定的)。
修复方案

方案1:调整自定义DataSource实现

修改datasource.ts代码

import { BehaviorSubject } from 'rxjs';

export class ListClientDataSource extends DataSource<Client> {
  // 替换为响应式的BehaviorSubject,初始化空数组避免undefined
  private dataSubject = new BehaviorSubject<Client[]>([]);
  paginator: MatPaginator;
  sort: MatSort;

  constructor(public clientService:  ClientService) {
    super();
    this.clientService.getClientsList().subscribe(result =>{
      // 数据返回后推送新值到数据流
      this.dataSubject.next(result.data);
    });
  }

  // 对外暴露data值供模板读取
  get data() {
    return this.dataSubject.value;
  }

  connect(): Observable<Client[]> {
    const dataMutations = [
      // 用响应式数据流代替静态的observableOf
      this.dataSubject.asObservable(),
      this.paginator.page,
      this.sort.sortChange
    ];

    return merge(...dataMutations).pipe(map(() => {
      // 从subject中取最新值做分页排序
      return this.getPagedData(this.getSortedData([...this.dataSubject.value]));
    }));
  }

  // 补充disconnect方法清理订阅,防止内存泄漏
  disconnect(): void {
    this.dataSubject.complete();
  }

  // 保留你原有的getPagedData、getSortedData方法即可,下面是示例实现
  private getPagedData(data: Client[]): Client[] {
    const startIndex = this.paginator.pageIndex * this.paginator.pageSize;
    return data.splice(startIndex, this.paginator.pageSize);
  }

  private getSortedData(data: Client[]): Client[] {
    if (!this.sort.active || this.sort.direction === '') {
      return data;
    }

    return [...data].sort((a, b) => {
      const isAsc = this.sort.direction === 'asc';
      switch (this.sort.active) {
        // 这里替换为你实际的排序字段逻辑
        case 'name': return compare(a.name, b.name, isAsc);
        case 'id': return compare(+a.id, +b.id, isAsc);
        default: return 0;
      }
    });
  }
}

// 排序工具函数
function compare(a: number | string, b: number | string, isAsc: boolean) {
  return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
}

其余代码无需修改

  • component.ts的逻辑保持不变即可,因为dataSubject.value默认是空数组,ngAfterViewInit中访问length也不会报错
  • 模板的[length]="dataSource?.data.length"无需调整,已经可以正常工作

方案2:使用Angular官方封装的MatTableDataSource(更简单)

如果没有特殊的自定义数据流需求,直接用官方提供的MatTableDataSource可以省去大量自定义逻辑,无需自己实现DataSource:

修改component.ts代码

import { MatTableDataSource } from '@angular/material/table';

export class ListClientComponent implements AfterViewInit, OnInit {
  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;
  // 直接使用官方数据源
  dataSource = new MatTableDataSource<Client>();
  
  constructor(public clientService: ClientService) { }

  displayedColumns = ['id', 'name', 'contact', 'email', 'date', 'iot', 'loc'];

  ngOnInit() {
    this.clientService.getClientsList().subscribe(result =>{
      this.dataSource.data = result.data;
    });
  }

  ngAfterViewInit() {
    this.dataSource.sort = this.sort;
    this.dataSource.paginator = this.paginator;
  }
}

修改模板代码

<mat-paginator #paginator 
      [length]="dataSource.data.length"
      [pageIndex]="0"
      [pageSize]="50"
      [pageSizeOptions]="[25, 50, 100, 250]">
</mat-paginator>

这个方案不需要自定义ListClientDataSource类,所有分页、排序、过滤逻辑官方都已经封装好,更稳定易维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 01:45:04