如果从父级重新初始化 FormGroup,自定义组件 FormControl 会中断
Posted
技术标签:
【中文标题】如果从父级重新初始化 FormGroup,自定义组件 FormControl 会中断【英文标题】:Custom component FormControl breaking if reinitializing FormGroup from parent 【发布时间】:2017-11-02 06:58:44 【问题描述】:从自定义组件中使用的父组件重新初始化 formGroup 时遇到问题。我得到的错误是:
没有 FormControl 实例附加到表单控件元素 名称:'selectedCompany'
HTML:
<form [formGroup]="addForm">
...
<my-custom-component formControlName="selectedCompany"></my-custom-component>
...
</form
<my-custom-component>
是按照创建自定义formControl组件的有效方式创建的:https://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html#implementing-controlvalueaccessor
组件
这是初始化formGroup变量addForm
的代码:
let formTemp: any =
selectedCompany: new FormControl(null, [Validators.required]),
this.addForm = this._formBuilder.group(formTemp);
第一次初始化addForm
一切都很好。但是当我重新打开表单所在的模态,并执行相同的组件代码时,就会出现上述错误。
【问题讨论】:
【参考方案1】:我发现一遍又一遍地重新初始化formGroup
是不好的,因为组件失去了对旧formGroup
的引用。
如果需要设置值来显示新鲜的形式,.setValue
是这里的解决方案:
组件
不要重新初始化addForm
,而是检查addForm
是否在之前被初始化过,如果是,只为现有的FormControls
设置值:
if (this.addForm)
this.addForm.setValue(
selectedCountry: null
)
else
let formTemp: any =
selectedCompany: new FormControl(null, [Validators.required]),
this.addForm = this._formBuilder.group(formTemp);
这样,我想,引用不会丢失到旧的addForm
,所以不会发生错误。
【讨论】:
如果您只想更新选定数量的属性/表单控件,也可以使用 [FormGroup].patchvalue(object) Mario,非常感谢您提供此解决方案,这比@zucker 的回答(所有其他人提供的顺便说一句)要好得多,而且我相信这个解决方案通常应该被视为默认表单创建。 【参考方案2】:我找到了一个奇怪的“解决方案”。因此,要重置子组件,这些子组件使用 formGroup 并在您将其换出时会感到困惑。我使用这个技巧。
comp.ts
public flicker: boolean = false;
reInit()
this.flicker = true;
this.addForm = this._formBuilder.group(
selectedCompany: new FormControl(null, [Validators.required]),
);
setTimeout( () => this.flicker = false, 200); //On very heavy pages, timeout ensures that the flicker hack works as expected.
comp.html
<form [formGroup]="addForm" *ngIf="!flicker">
...
<my-custom-component formControlName="selectedCompany"></my-custom-component>
...
</form>
可怕的 hack,它基本上强制 formGroup 组件自行销毁并重新初始化,但绝望的时候需要绝望的措施......
我需要这个技巧,因为我使用 FormGroup 对象将表单的结果保存到临时结果数组中,每个结果都可以随意重新打开和编辑。将来我会做基于 ngModel 的表单状态保存,以避免这个问题,但这里有一个临时解决方案。
编辑 1
setTimeout( () => this.flicker = false, 200); //On very heavy pages, timeout ensures that the flicker hack works as expected.
有更好的方法来同步闪烁
this.flicker = true;
this._changeDetectorRef.detectChanges();
this.flicker = false;
this._changeDetectorRef.detectChanges();
检测更改将同步运行更改检测并更新视图,从而删除旧的表单组。
【讨论】:
是的,对于您使用反应式表单解决方案的用例。【参考方案3】:我的解决方案是将formControlName
替换为formControl
。
而不是
<my-custom-component formControlName="selectedCompany"></my-custom-component>
使用
<my-custom-component [formControl]="addForm.controls['selectedCompany']"></my-custom-component>
或者用一些getMethod来获取formControl
也适用于错误:
没有 FormControl 实例附加到表单控件元素 路径
我用过一些FormArray
。
【讨论】:
这就是我使用新的 DateRange 和 Angular 材料的原因。谢谢以上是关于如果从父级重新初始化 FormGroup,自定义组件 FormControl 会中断的主要内容,如果未能解决你的问题,请参考以下文章
将自定义组件添加到反应式表单的 FormGroup 的正确方法是啥?
React Native - 如何从父级获取 FlatList 项的值