在加载我的父组件时,我正在使用patchValue更新该(父)组件的形式.
在我的孩子ControlValueAccessor组件的表单组件上也有一个表单组.因此,在我的writeValue函数中,我正在更新子组件有关从父组件patchValue传递的值.
我的writeValue函数看起来像这样:
writeValue(value: CountryAndCity): void { if (value != null && value.country && value.city) { this.isDefaultValueDefined = true; this.form.patchValue({country: value.country}); this.form.patchValue({city: value.city}); **this.cdRef.detectChanges();** } }
正如你所看到的,我不得不使用detectChanges()作为上述函数的最后一行,因为没有它我得到错误:
ParentComponent.html:1错误错误:ExpressionChangedAfterItHasBeenCheckedError:表达式在检查后已更改.上一个值:’ng-pristine:true’.当前值:’ng-pristine:false’.
我想我明白为什么会这样. Angular开始检查父组件,然后,开始检查子组件,在子组件上,子组件,在writeValue函数上更改父组件的表单状态.
我对使用detectChanges()感到不舒服.有没有办法做别的事情?是否必须使用父组件和子组件,每个组件都有formGroup,子组件是父formgroup formControl之一?
解决方法
我不认为,这是因为你的写函数而发生的,而是你的表单中的某些内容在创建子项后立即发出值,但是如果没有看到更多的代码就很难分辨.
我遇到了同样的问题,所以我在没有手动触发变化检测的情况下防止此错误的做法是将值传播与当前更改检测周期中的父传播分离.
实现这一目标的一个简单方法就是在上游产生价值
this.form .valueChanges .pipe( delay(0) ) .subscribe(it => { this.propagateChange(...) })
我不知道这是否是最好的方法,但对我来说它是有效的.
顺便说一句:我还建议使用{emitEvent:false}作为补丁选项,这可以防止子进程在写入函数中触发事件.如果您对错误来源的假设是正确的,那么这将解决您的问题,但如果我的假设是真的则不会.