Mat-table排序失效:未用setTimeout时this.sort为undefined的解决方法
解决Mat-table动态数据/列时Sort为undefined的问题
问题场景
动态变更数据和列配置的Mat-table,设置排序功能时出现this.sort为undefined的情况,临时用2秒setTimeout可以解决,但这是不合理的临时方案。
原因分析
- 表格通过
*ngIf="!isLoading"控制渲染,数据加载完成前表格未初始化,@ViewChild(MatSort)无法获取到实例 - 动态生成列的过程中,MatSort的初始化时机滞后于数据订阅完成的时间点,直接赋值时Sort实例还未创建
正确解决方案
方案1:手动触发变更检测+视图更新后赋值
在数据加载完成、更新列和数据后,手动触发变更检测确保表格渲染,再给dataSource设置Sort:
import { Component, ViewChild, AfterViewInit, ChangeDetectorRef } from '@angular/core'; import { MatSort } from '@angular/material/sort'; import { MatTableDataSource } from '@angular/material/table'; @Component({ // 组件元数据(如selector、templateUrl等) }) export class YourTableComponent implements AfterViewInit { @ViewChild(MatSort, { static: false }) sort: MatSort; dataSource = new MatTableDataSource<any>(); isLoading = true; displayedColumns: string[] = []; data: any[] = []; filteredData: any; // 你的过滤数据 constructor(private _service: YourDataService, private cdr: ChangeDetectorRef) {} ngAfterViewInit() { this.getData(1); } changeData(id: number) { this.getData(id); } getData(id: number) { this.isLoading = true; this._service.GetData(id, this.filteredData).subscribe(res => { // 更新列配置与表格数据 this.data = res.columns; this.displayedColumns = res.columns .filter(col => col.ColumnIsVisible) .map(col => col.ColumnName); this.dataSource.data = res.tableData; this.isLoading = false; // 强制触发变更检测,确保表格(含MatSort)完成渲染 this.cdr.detectChanges(); // 此时Sort实例已可用,直接赋值 if (this.sort) { this.dataSource.sort = this.sort; } }); } }
方案2:利用AfterViewChecked钩子监听视图变化
在每次视图更新完成后检查Sort实例是否可用,若可用则赋值给dataSource:
import { Component, ViewChild, AfterViewInit, AfterViewChecked } from '@angular/core'; import { MatSort } from '@angular/material/sort'; import { MatTableDataSource } from '@angular/material/table'; @Component({ // 组件元数据 }) export class YourTableComponent implements AfterViewInit, AfterViewChecked { @ViewChild(MatSort, { static: false }) sort: MatSort; dataSource = new MatTableDataSource<any>(); isLoading = true; displayedColumns: string[] = []; data: any[] = []; filteredData: any; constructor(private _service: YourDataService) {} ngAfterViewInit() { this.getData(1); } // 每次视图更新后触发 ngAfterViewChecked() { // 仅当Sort存在且dataSource未设置Sort时赋值 if (this.sort && !this.dataSource.sort) { this.dataSource.sort = this.sort; } } changeData(id: number) { this.getData(id); } getData(id: number) { this.isLoading = true; this._service.GetData(id, this.filteredData).subscribe(res => { this.data = res.columns; this.displayedColumns = res.columns .filter(col => col.ColumnIsVisible) .map(col => col.ColumnName); this.dataSource.data = res.tableData; this.isLoading = false; }); } }
说明
两种方案都能避免依赖setTimeout的不确定性:
- 方案1通过手动触发变更检测,主动确保表格渲染完成后再赋值Sort,性能更优
- 方案2利用Angular生命周期钩子,被动监听视图变化,实现更简洁
内容的提问来源于stack exchange,提问作者Silver Origami
相关产品推荐
相关产品推荐

