在使用 时,Angular 6 报了 ExpressionChangedAfterItHasBeenCheckedError 错误。
在使用 时,Angular 6 报了 ExpressionChangedAfterItHasBeenCheckedError 错误。
我在Angular 6中遇到以下错误:
当我移除第二个`mat-tab
`时,错误消失了。在其他类似的组件中,我没有将这两个表单放在`mat-tab-group
`和`mat-tab
`中,也没有这个错误。花了一段时间找出差异所在。
错误信息如下:
ExpressionChangedAfterItHasBeenCheckedError: 表达式在检查之后发生了变化。之前的值为'ng-valid: true',当前的值为'ng-valid: false'。
环境如下:
Angular CLI: 6.2.8
Node: 11.9.0
OS: linux x64
Angular:
ts文件(export class ElectricityRateListComponent extends SelectableEntitiesListComponent)如下:
public displayedColumnsArray = [ 'select', 'id', 'energyRate', 'mainTransmissionRate', 'publicServiceRate', 'validityStartDate', 'validityEndDate', 'electricityType', 'city', ]; public statusMessage: string = '' public selectedTabIndex: number = 0 protected _elTypeAddSelect: DBEntitySelect//ElectricityType: Enumerate protected _elTypeEditSelect: DBEntitySelect //ElectricityType: Enumerate protected _cityAddSelect: DBEntitySelect //City: Enumerate protected _cityEditSelect: DBEntitySelect //City: Enumerate constructor( protected router: Router, public messageService: MessageService, protected logger: LoggerService, protected route: ActivatedRoute, protected entitiesService: ElectricityRateService, protected enumeratesService: EnumerateService, protected formBuilder: FormBuilder, public formService: DynamicFormService, iconRegistry: MatIconRegistry, sanitizer: DomSanitizer, // private location: Location ) { super(router, messageService, logger, route, entitiesService, formBuilder, formService, iconRegistry, sanitizer, new ElectricityRate()); (...) } /** * Common to add and edit forms * * @param aStrangeObject */ protected _getCommonFormControlModel(aStrangeObject: Enumerate): DynamicFormControlModel[] { let lEntity: ElectricityRate = new ElectricityRate().deserialize( aStrangeObject ) console.debug( "-----getAddFormControlModel->", aStrangeObject, lEntity.validityStartDate.constructor.name, lEntity.validityEndDate.constructor.name ) const result: DynamicFormControlModel[] = [ new DynamicInputModel({ id: "energyRate", label: "Energy Rate", value: lEntity.energyRate, inputType: DYNAMIC_FORM_CONTROL_INPUT_TYPE_NUMBER, min: ElectricityRate.MIN_ELECTRICITY_RATE, max: ElectricityRate.MAX_ELECTRICITY_RATE, placeholder: "Energy Rate" }), new DynamicInputModel({ id: "mainTransmissionRate", label: "Transmission Rate", inputType: DYNAMIC_FORM_CONTROL_INPUT_TYPE_NUMBER, min: ElectricityRate.MIN_ELECTRICITY_RATE, max: ElectricityRate.MAX_ELECTRICITY_RATE, value: lEntity.mainTransmissionRate.toString(), placeholder: "Transmission Rate" }), new DynamicInputModel({ id: "publicServiceRate", label: "Public Service Rate", inputType: DYNAMIC_FORM_CONTROL_INPUT_TYPE_NUMBER, min: ElectricityRate.MIN_ELECTRICITY_RATE, max: ElectricityRate.MAX_ELECTRICITY_RATE, value: lEntity.publicServiceRate.toString(), placeholder: "Public Service Rate" }), new DynamicInputModel({ id: "validityStartDate", label: "Validity start date", inputType: DYNAMIC_FORM_CONTROL_INPUT_TYPE_DATE, maxLength: 10, value: MiscHelper.dateToDynamicInputDate(lEntity.validityStartDate), placeholder: "Validity start date" }), new DynamicInputModel({ id: "validityEndDate", label: "Validity end date", inputType: DYNAMIC_FORM_CONTROL_INPUT_TYPE_DATE, value: MiscHelper.dateToDynamicInputDate(lEntity.validityEndDate), placeholder: "Validity end date" }) ] return result } /** * called by SelectableEntitiesListComponent->onInit * * @param aStrangeObject */ protected _getAddFormControlModel(aStrangeObject: Enumerate): DynamicFormControlModel[] { //console.debug('getAddFormControlModel->aStrangeObject:', aStrangeObject) let lEntity: Enumerate = new Enumerate().deserialize(aStrangeObject) console.debug('-----getAddFormControlModel->aStrangeObject, lEntity:', aStrangeObject, lEntity) //Add form fields const result: DynamicFormControlModel[] = this._getCommonFormControlModel(aStrangeObject) result.push(this._elTypeAddSelect.asDynamicInputModel()) result.push(this._cityAddSelect.asDynamicInputModel()) return result } /** * Built onRowClicked * * @param anId * @param aStrangeObject can be a row of dataTable */ protected _getEditFormControlModel(aStrangeObject: Enumerate): DynamicFormControlModel[] { console.log('getEditFormControlModel:', aStrangeObject) let result = this._getCommonFormControlModel(aStrangeObject) result = result.concat(DBEntity.getIdFormControlModel('id', aStrangeObject)) result.push(this._elTypeEditSelect.asDynamicInputModel()) result.push(this._cityEditSelect.asDynamicInputModel()) // console.log('getEditFormControlModel:', result) return result }
与这篇文章高度相关。
Angular 6中使用
在使用
解决这个问题的一个可能的方法是,在ngAfterViewInit()中对数据源进行排序之前,使用setTimeout或delay(0)延迟一段时间。这样做的原因是,让Angular首先显示loading flag为false的数据。
这种解决方法的原理是:
1. loading指示器的初始值为false,因此初始时不会显示loading指示器。
2. ngAfterViewInit()被调用,但是数据源不会立即被调用,所以不会通过ngAfterViewInit()同步地进行加载指示器的修改。
3. Angular完成视图渲染,并在屏幕上反映最新的数据变化,JavaScript VM转换完成。
4. 一段时间后,setTimeout()调用(也可以在delay(0)内部使用),然后数据源加载其数据。
5. loading flag设置为true,现在显示loading指示器。
6. Angular完成视图渲染,并在屏幕上反映最新的变化,这导致loading指示器显示出来。
除了使用setTimeout,还可以使用changeDetector.detectChanges()作为另一种可能的解决方法。changeDector是一个注入的ChangeDetectorRef,这是解决这个问题的另一种广泛使用的方法。
您还可以使用Promise.resolve作为setTimeout的替代方法。
以上解决方法的具体情况可以在Angular官方文档以及stackoverflow上的相关回答中找到更详细的解释和示例。
希望这些信息对您有所帮助!