Angular 9 mat-table 和 ExpressionChangedAfterItHasBeenCheckedError

Jos*_*ers 1 angular-material angular mat-table

我有一个 Angular 9,打开了 Ivy,组件有多个垫子表。一张表的行中的输入字段绑定到反应式表单。我将表绑定到表单数组。这很好用...但是,当我加载带有值的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];

}
Run Code Online (Sandbox Code Playgroud)

表格 HTML(已修剪):

<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>   
Run Code Online (Sandbox Code Playgroud)

不确定如何解决此问题?我在加载表单中的项目后收到错误。我可以维护两个列表……一个用于表格,一个用于表单,但这会是怎样的 PIA 呢?我缺少什么?

alo*_*lou 5

如果我没有遗漏你所描述的一些重要的东西,你应该尝试

  • 在变更检测中保持 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();

 }
Run Code Online (Sandbox Code Playgroud)

发生了什么?

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

通过设置 onPush 策略,您可以告诉 Angular 仅在 @Input 更改时触发更改检测,否则该节点将被忽略。这样就可以修复错误,但您仍然需要手动触发更改检测,以便显示更新的数据。