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

Angular Material Table(mat-sort-header)报错:无法定义__source属性

解决Angular Material MatSort控制台报错:TypeError: Cannot define property __source, object is not extensible

问题概述

表格显示与排序功能可正常使用,但控制台持续抛出上述错误,错误指向MatSort类对象无法添加__source扩展属性。

错误原因分析

结合代码与报错信息,核心问题集中在以下几点:

  1. 生命周期内重复绑定Sort:ngOnInit与ngAfterViewInit中两次对dataSource.sort赋值,导致MatSort实例被重复注册,触发内部扩展属性操作失败。
  2. 模板列定义不规范:存在嵌套的ng-container matColumnDef(select列定义内嵌套receiptNumber列),违反Angular Material表格列定义规则,可能导致排序头注册异常。
  3. 初始排序配置不一致:模板matSortActive="deliveryDate"与组件内设置的active: "receiptDate"字段不匹配,引发内部状态冲突。

解决方案

1. 统一DataSource初始化逻辑

删除ngOnInit中的Sort绑定操作,仅在ngAfterViewInit中完成DataSource初始化与Sort绑定,避免重复操作:

export class ReceiptComponent implements OnInit, AfterViewInit {
  @ViewChild(MatSort, { static: true }) sort: MatSort;
  dataSource = new MatTableDataSource<any>();
  displayedColumns = [
    "receiptNumber", 
    "receiptDate", 
    "description", 
    "customerName", 
    "salesPersonName",
    "actions"
  ];

  receiptList: Receipts[] = [];

  ngOnInit() {
    const sortState: Sort = {
      active: "receiptDate", 
      direction: 'desc'
    };
    this.sort.active = sortState.active;
    this.sort.direction = sortState.direction;
  }

  ngAfterViewInit() {
    this.dataSource = new MatTableDataSource(this.receiptList);
    this.dataSource.sort = this.sort;
    // 可选:直接触发初始排序
    this.sort.sort({id: 'receiptDate', start: 'desc'});
  }
  // ...其他业务代码
}

2. 修正模板列定义

移除嵌套的列定义,每个matColumnDef单独使用ng-container:

<mat-table 
  class="lmat-elevation-z8" 
  [dataSource]="dataSource" 
  matSort
  matSortActive="receiptDate" <!-- 与组件初始排序字段保持一致 -->
  matSortDisableClear>

  <!-- 单独定义select列 -->
  <ng-container matColumnDef="select">
    <!-- 补充select列的表头与单元格代码 -->
  </ng-container>

  <ng-container matColumnDef="receiptNumber">
    <mat-header-cell 
      *matHeaderCellDef 
      mat-sort-header 
      [hidden]="!dropdownList[0].isActiveColumn">
        RMT Number
    </mat-header-cell>
    <mat-cell 
      *matCellDef="let rt" 
      [hidden]="!dropdownList[0].isActiveColumn">
        {{ rt.receiptNumber }}
    </mat-cell>
  </ng-container>

  <ng-container matColumnDef="receiptDate">
    <mat-header-cell 
      *matHeaderCellDef 
      mat-sort-header 
      [hidden]="!dropdownList[1].isActiveColumn">
        Receipt Date <!-- 修正表头文本与字段名不一致问题 -->
    </mat-header-cell>
    <mat-cell 
      *matCellDef="let rt" 
      [hidden]="!dropdownList[1].isActiveColumn">
        {{ rt.receiptDate }}
    </mat-cell>
  </ng-container>
  <!-- ...其他列定义 -->
</mat-table>

3. 确保数据对象可扩展

若上述修改后仍报错,检查receiptList中的数据对象是否被Object.freeze()或其他方式设置为不可扩展,Angular Material处理数据时需要扩展对象属性,可通过解构创建新对象解除限制:

// 示例:从接口获取数据后转换为可扩展对象
this.receiptList = apiResponse.data.map(item => ({...item}));

验证步骤

  1. 重启应用,检查控制台是否仍有报错
  2. 测试各列排序功能是否正常
  3. 确认列显示/隐藏功能正常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 21:30:52