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

NG0100错误求助:ExpressionChangedAfterItHasBeenCheckedError排查

解决Angular表格列隐藏功能引发的NG0100错误

问题根源

NG0100错误(ExpressionChangedAfterItHasBeenCheckedError)是因为你在Angular变更检测完成后的ngAfterViewChecked钩子中修改了displayedColumns的值,导致Angular检测到表达式在检查后发生了变化。当前在ngAfterViewChecked里调用getDisplayedColumns()的操作直接触发了这个问题。

解决方案

1. 删除ngAfterViewChecked钩子

直接移除这个钩子方法,避免在变更检测完成后修改组件状态:

// 删掉这个方法
// ngAfterViewChecked(){
//   this.getDisplayedColumns();
// }

2. 优化列定义的初始化逻辑

不要在类属性初始化阶段直接依赖FormControl的value(此时组件还未完成初始化,this.name!.value可能不是预期值),改为在ngOnInit中初始化列定义:

ngOnInit(): void {
  // 初始化列定义,设置初始隐藏状态
  this.columnDefinitions = [
    { def: 'name', label: 'name dom', hide: !this.name!.value },
    // 其他列定义...
  ];
  // 初始化显示列
  this.getDisplayedColumns();

  this.domSerice.getAllDom().subscribe(x =>{
    this.dataSource = new MatTableDataSource<Dom>(x);
    this.dataSource.filterPredicate = this.customFilterPredicate();
  })
}

3. 在列隐藏开关的valueChanges中同步更新显示列

在ngAfterViewInit的merge订阅里,更新columnDefinitions后立即调用getDisplayedColumns(),确保变更发生在变更检测周期内:

ngAfterViewInit() {
  let o1:Observable<boolean> = this.name!.valueChanges;
  // ...其他Observable定义

  merge(o1,o2,o3,o4,o5,o6,o7,o8).subscribe( {
    next: (v)=>{
      // 更新对应列的隐藏状态
      this.columnDefinitions[0].hide = !this.name!.value;
      // ...其他列的hide更新逻辑
      // 立即更新显示列
      this.getDisplayedColumns();
    }
  });

  // 在这里设置分页和排序,确保ViewChild实例已加载
  this.dataSource.paginator = this.paginator;
  this.dataSource.sort = this.sort;

  // ...其他筛选逻辑
}

4. 可选:手动触发变更检测(如果仍有问题)

如果偶尔还是出现变更检测异常,可以注入ChangeDetectorRef手动标记变更:

// 构造函数中注入
constructor(
  private _httpClient: HttpClient,
  private _liveAnnouncer: LiveAnnouncer,
  private cdr: ChangeDetectorRef // 新增
) {
  this.domSerice = new DomService(this._httpClient);
}

// 在valueChanges订阅中调用
merge(o1,o2,o3,o4,o5,o6,o7,o8).subscribe( {
  next: (v)=>{
    this.columnDefinitions[0].hide = !this.name!.value;
    // ...其他列更新
    this.getDisplayedColumns();
    this.cdr.detectChanges(); // 手动触发变更检测
  }
});

5. 修复分页和排序的设置时机

原代码在ngOnInit中设置this.dataSource.paginator = this.paginator时,paginator还未被@ViewChild获取到(ViewChild在ngAfterViewInit阶段才会赋值),所以必须把这部分逻辑移到ngAfterViewInit中,确保实例已存在。

修改后的核心代码片段

export class DomTableComponent implements OnInit, AfterViewInit {

  filterValues: any = {name:'',...};
  filterSelectObj: any[] = [];

  form:FormGroup = new FormGroup({
    name: new FormControl(true),
    ...
  });

  name = this.form.get('name');
  ...

  // 先声明列定义数组,后初始化
  columnDefinitions: Array<{def: string, label: string, hide: boolean}> = [];

  nameFilter = new FormControl();
  ...
  globalFilter = '';

  displayedColumns: string[] = [];

  empFilters: EmpFilter[]=[];
  
  domSerice: DomService;
  dataSource= new MatTableDataSource<Dom>([]);

  @ViewChild(MatPaginator) paginator!: MatPaginator;
  @ViewChild(MatSort) sort!: MatSort;

  constructor(
    private _httpClient: HttpClient,
    private _liveAnnouncer: LiveAnnouncer,
    private cdr: ChangeDetectorRef // 新增
  ) {
    this.domSerice = new DomService(this._httpClient);
   }

  ngOnInit(): void {
    // 初始化列定义
    this.columnDefinitions = [
      { def: 'name', label: 'name dom', hide: !this.name!.value},
      ...
    ];
    // 初始化显示列
    this.getDisplayedColumns();

    this.domSerice.getAllDom().subscribe(x =>{
      this.dataSource = new MatTableDataSource<Dom>(x);
      this.dataSource.filterPredicate = this.customFilterPredicate();
    })
  }

  ngAfterViewInit() {
    let o1:Observable<boolean> = this.name!.valueChanges;
    ...
 
    merge(o1,o2,o3,o4,o5,o6,o7,o8).subscribe( {
      next: (v)=>{
        this.columnDefinitions[0].hide = !this.name!.value;
        ...
        this.getDisplayedColumns();
        this.cdr.detectChanges(); // 可选:手动触发变更检测
      }
    });

    // 正确设置分页和排序
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;
 
    this.nameFilter.valueChanges.subscribe((filterValue) => {
      this.filterValues['name'] = filterValue;
      this.dataSource.filter = JSON.stringify(this.filterValues);
    });
    ...
  }

  // ...其他方法保持不变

  getDisplayedColumns() {
    this.displayedColumns = this.columnDefinitions.filter(cd=>!cd.hide).map(cd=>cd.def);
  }
  
}

修复逻辑说明

  • 移除ngAfterViewChecked中的状态修改,避免在变更检测完成后触发值变更。
  • 将列定义的初始化移到ngOnInit,确保依赖的FormControl已完成初始化。
  • 在列开关的valueChanges订阅中直接更新显示列,确保变更发生在Angular的变更检测周期内。
  • 修正paginator和sort的设置时机,确保实例已被正确获取。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 16:05:24