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 发生变化时才触发变化检测,否则该节点将被忽略。这样就修复了错误,但您仍然需要手动触发更改检测,以显示更新的数据。
我有一个 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 发生变化时才触发变化检测,否则该节点将被忽略。这样就修复了错误,但您仍然需要手动触发更改检测,以显示更新的数据。