带有表单组的子 ControlValueAccessor 组件 - 检查后表达式已更改
Posted
技术标签:
【中文标题】带有表单组的子 ControlValueAccessor 组件 - 检查后表达式已更改【英文标题】:Child ControlValueAccessor Component with formgroup - expression has changed after it was checked 【发布时间】:2018-08-02 01:51:47 【问题描述】:在加载我的 父 组件时,我正在使用 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 ERROR 错误:ExpressionChangedAfterItHasBeenCheckedError:表达式在检查后已更改。以前的值:'ng-pristine: true'。当前值:'ng-pristine: false'。
我想我明白为什么会这样。 Angular 开始检查父组件,然后,开始检查子组件,然后,在子组件上,在子组件上,在 writeValue 函数上更改父组件的表单状态。
我对使用 detectChanges() 感到不舒服。有没有办法做其他事情?使用父组件和子组件时是否必须每个组件都有formGroup,并且子组件是父formgroup formControl之一?
【问题讨论】:
您好,您的问题解决了吗? 【参考方案1】:我不认为这是因为您的 write
函数而发生的,而是您的表单中的某些内容在孩子创建后立即发出值,但是如果不查看更多代码就很难判断.
我遇到了同样的问题,所以我在不手动触发更改检测的情况下防止此错误的方法是将值传播与当前的更改检测周期分离到父级。
实现这一点的一个简单方法是在上游的值中 yield
喜欢
this.form
.valueChanges
.pipe(
delay(0)
)
.subscribe(it =>
this.propagateChange(...)
)
我不知道这是否是最好的方法,但对我来说它有效。
顺便说一句:我还建议使用emitEvent: false
作为补丁选项,这可以防止孩子在write
函数中触发事件。如果您对错误来源的假设正确,这将解决您的问题,但如果我的假设正确,则不会。
【讨论】:
【参考方案2】:Angular 应用程序状态变化可能来自:
活动 XHR 定时器但是当您使用 Control Value Accessor 写入值时,您需要使用 ChangeDetectorRef
和 detectChanges()
告诉 angular update 更改
你应该看看 Pascal Precht 文章的这部分 Who notifies Angular
【讨论】:
【参考方案3】:你的方法很好,@Tobi 的回答也很好!
也就是说,如果您不想在构建嵌套表单(使用子组件)/创建自定义控件值访问器方面付出太多努力,您绝对应该查看这个库:https://github.com/cloudnc/ngx-sub-form
如果您使用该库,您遇到的错误绝不会发生,因为我们处理这种情况的方式与 Tobi 非常相似。
从您的角度来看,它只需要您扩展一个类而不是更多!还将为您提供类型安全、访问嵌套错误等。
我还回答了一个关于如何构建复杂/嵌套/子表单的问题,这可能会让你感兴趣https://***.com/a/56375605/2398593
编辑:
如果你想更进一步,我刚刚发布了一篇博文,在这里https://dev.to/maxime1992/building-scalable-robust-and-type-safe-forms-with-angular-3nf9
解释了很多关于表单和 ngx-sub-form 的事情【讨论】:
以上是关于带有表单组的子 ControlValueAccessor 组件 - 检查后表达式已更改的主要内容,如果未能解决你的问题,请参考以下文章