Angular Material Table(mat-sort-header)报错:无法定义__source属性
解决Angular Material MatSort控制台报错:TypeError: Cannot define property __source, object is not extensible
问题概述
表格显示与排序功能可正常使用,但控制台持续抛出上述错误,错误指向MatSort类对象无法添加__source扩展属性。
错误原因分析
结合代码与报错信息,核心问题集中在以下几点:
- 生命周期内重复绑定Sort:
ngOnInit与ngAfterViewInit中两次对dataSource.sort赋值,导致MatSort实例被重复注册,触发内部扩展属性操作失败。 - 模板列定义不规范:存在嵌套的
ng-container matColumnDef(select列定义内嵌套receiptNumber列),违反Angular Material表格列定义规则,可能导致排序头注册异常。 - 初始排序配置不一致:模板
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}));
验证步骤
- 重启应用,检查控制台是否仍有报错
- 测试各列排序功能是否正常
- 确认列显示/隐藏功能正常
内容的提问来源于stack exchange,提问作者kt167
相关产品推荐
相关产品推荐

