Angular 9 mat-table 和 ExpressionChangedAfterItHasBeenCheckedError

Angular 9 mat-table and ExpressionChangedAfterItHasBeenCheckedError

我有一个 Angular 9,带有 Ivy,组件有多个垫子-table。一个 table 包含输入字段绑定到反应式表单的行。我将 table 绑定到表单数组。这很好用......但是,当我用值加载 formarray 时,我得到了有趣的“ExpressionChangedAfterItHasBeenCheckedError:表达式在检查后已更改。'ng-valid' 的先前值:'true'。当前值:'false'" 错误。

此外,如果我在组件上设置 changeDetection: ChangeDetectionStrategy.OnPush,它工作正常,但我显然失去了变化检测...

这是我的设置(经过修剪):

反应形式:

quoteForm = new FormGroup({
    QuoteNumber:new FormControl(''),
    ContractTerm:new FormControl(''),
    ContractStartDate:new FormControl(''),
    QuoteName: new FormControl('', Validators.required),
   ...
    Items: this.fb.array([])
  });



async ngOnInit(): Promise<void> {
  ...
  this.QuoteItems = await this.CIM.GetQuoteItems(this.CurrentQuoteNumber);
  const itemsArray = this.quoteForm.get('Items') as FormArray;
  ...
  this.QuoteItems.forEach(item => {
      let NewObj = this.fb.group({
      isNew:false,
     ...
     });
     ...
     itemsArray.push(NewObj);
   });    
  }

  this.ItemdataSource=new MatTableDataSource(this.quoteForm.get('Items').value);
  this.ItemdataSource.paginator = this.paginator.toArray()[0];

}

tableHTML(修剪):

<table mat-table [dataSource]="ItemdataSource" multiTemplateDataRows formArrayName="Items"> 
...
 <tr mat-header-row *matHeaderRowDef="ItemColumns"></tr>
 <tr mat-row *matRowDef="let row; columns: ItemColumns;" class="element-row" [class.expanded-row]="expandedElement === row" (click)="expandedElement = expandedElement === row ? null : row"></tr>
 <tr mat-row *matRowDef="let row; columns: ['SerialNumbers']" class="detail-row"></tr>
  </table>       
</div>
<mat-paginator [pageSizeOptions]="[20, 40, 100]" showFirstLastButtons></mat-paginator>   

不确定如何解决这个问题?我在用项目加载表单后收到错误。我可以维护两份清单……一份用于 table,一份用于表格,但那会是怎样的 PIA?我错过了什么?

如果我没有遗漏你描述的重要内容,你应该试试

  • 在变更检测中保持 onPush 策略
  • 在您的异步代码求值后手动触发 detectChanges

因此,您的组件将类似于:

import { ..., ChangeDetectorRef } from '@angular/core';

@Component({
  ...
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class YourComponent ... {

  constructor(private cdRef: ChangeDetectorRef) { }


  async ngOnInit(): Promise<void> {
    ...
    this.QuoteItems = await this.CIM.GetQuoteItems(this.CurrentQuoteNumber);
    const itemsArray = this.quoteForm.get('Items') as FormArray;
    ...
    this.QuoteItems.forEach(item => {
      let NewObj = this.fb.group({
        isNew:false,
        ...
      });
      ...
      itemsArray.push(NewObj);
    });    
   }

   this.ItemdataSource = new MatTableDataSource(this.quoteForm.get('Items').value);
   this.ItemdataSource.paginator = this.paginator.toArray()[0];

   this.cdRef.detectChanges();

 }

发生了什么事?

在开发模式下,angular 在渲染后立即检查/比较视图,以查看在上次更改检测和渲染后是否有任何数据更改。 因此,触发错误是因为数据在上次呈现视图内容后发生更改。

通过设置 onPush 策略,您告诉 angular 只有当 @Input 发生变化时才触发变化检测,否则该节点将被忽略。这样就修复了错误,但您仍然需要手动触发更改检测,以显示更新的数据。