angular - 从父组件更改嵌套表单字段值
问题描述
假设我有一个实现 CVA(控制值访问器)的嵌套表单。
// Child component which implements CVA
this.addressForm = new FormGroup({
city: new FormControl()
postalCode: new FormControl(null)
})
// Parent component html
<form [formGroup]= "productForm">
<input formControlName="date">
<address-form formControlName="addressForm"> </address-form>
</form>
// Parent component ts
this.productForm = new FormGroup({
date: new FormControl(null),
addressForm: new FormControl(null)
});
现在我只想修补 city
addresForm 的字段,所以我尝试了:
// This will set other values of addressForm to null.
this.productForm.get('addressForm').patchValue({city: 'some-city'});
// This below will not work.
this.productForm.get('addressForm.city').patchValue('some-city');// error no city control.
// Another workaround is using ControlContainer instead to link to parent
Instead of this:
// this.addressForm = new FormGroup({
// city: new FormControl()
// postalCode: new FormControl(null)
//})
using this on child
this.addressForm = this.controlContainer.control as FormGroup;
and declare formGroup on Parent.
this.productForm = new FormGroup({
date: new FormControl(null),
addressForm: new FormGroup({city: new FormControl(null), postalCode: new FormControl(null) })
});
BUT in this workaround, writeValue method is not called on Child.
由于它是 formControlName 保存单个值,因此其他值被重置。那么如何在不重置其他字段值的情况下设置嵌套表单字段值呢?
换句话说,我们如何控制来自父级的嵌套表单组件字段,例如修补值或监听特定字段值的变化? 堆栈闪电战网址
解决方案
粗俗,你在一个formGroup中没有一个formGroup,你只有一个带有两个FormControls的FormGroup,最后一个存储一个对象。
一般来说,当我们使用 FormGroup 时,我们可以采取两种方法
1.-在父级中定义完整的FormGroup,并将内部的FormGroup传递给子级
this.productForm = new FormGroup({
date: new FormControl(null),
addressForm: new FormGroup({ //see that adressForm is a FormGroup
city: new FormControl()
postalCode: new FormControl(null)
})
});
我们的孩子是一个简单的组件 - 没有实现 controlValue Accesor
//declare a variable "form"
form:FormGroup
//in a input asign the variale to the form
@Input('addressForm') _ set(value)
{
this.form=value as FormGroup
}
<!--we control the formGroup as another formGroup-->
<form [formGroup]="form">
<input formControlName="city">
<input formControlName="postalCode">
</form>
我们在父母中使用
<form [formGroup]= "productForm">
<input formControlName="date">
<!--see that pass as @Input the formGroup-->
<address-form [addressForm]="productForm.get('addressForm')"> </address-form>
</form>
2.-创建管理对象 {city:..postalCode:..} 的自定义表单控件
export class CustomAddressComponent implements ControlValueAccessor,OnDestroy {
form: FormGroup = new FormGroup({
city: new FormControl(),
postalCode: new FormControl(null)
});
subscription:any
onChange = (obj: any) => {};
onTouched = () => {};
writeValue(obj: any) {
this.form.patchValue(obj);
this.subscription=this.form.valueChanges.subscribe(res=>this.onChange(res))
}
registerOnChange(onChange: any) {
this.onChange = onChange;
}
registerOnTouched(onTouched: any) {
this.onTouched = onTouched;
}
setDisabledState(disabled: boolean) {
this.form[disabled ? 'disable' : 'enable']();
}
ngOnDestroy()
{
this.subscription.unsubscribe()
}
并在父母中使用
productForm = new FormGroup({
date: new FormControl(null),
addressForm: new FormControl(null) //<--see that is only a FormControl
});
<form [formGroup]="productForm2">
<input formControlName="date">
<!--use formControlName, it's like another input!-->
<custom-address-form formControlName="addressForm"> </custom-address-form>
</form>
在stackblitz中,您有两种方法。看到 form.value 在两种情况下都具有相同的结构
注意:真的要管理 FormGroup,我更喜欢使用简单的方法(使用组件),仅使用自定义表单控件来“更多”而不是组 FormControls。
NOTE2:自定义表单控件制作快速,仅用于演示
更新真的有其他方法,我们可以,例如创建我们的表格
productForm = new FormGroup({
date: new FormControl(null),
addressForm: new FormGroup({}) //<--an empty FormGroup
});
我们的组件创建表单
form:FormGroup
@Input('addressForm') set _(value:any)
{
this.form=value as FormGroup;
this.form.addControl('city',new FormControl())
this.form.addControl('postalCode',new FormControl())
}
甚至使用 FormGroupDirective 来访问一个 Form 并创建一个像
productForm3 = new FormGroup({
date: new FormControl(null), //<--see that we don't add anything more
});
并使用类似的组件
form: FormGroup;
constructor(
@Host() private formGroupDirective: FormGroupDirective,
@Attribute('groupName') private name
) {}
ngOnInit() {
setTimeout(() => {
this.formGroupDirective.form.addControl(
this.name,
new FormGroup({
city: new FormControl(),
postalCode: new FormControl()
})
);
console.log(this.formGroupDirective.form.value);
this.form = this.formGroupDirective.form.get(this.name) as FormGroup;
});
}
还有我们的父组件:
<form [formGroup]="productForm3">
<input formControlName="date">
<!--see that only put our component yet add the formGroup-->
<address-form-three groupName='addressForm'> </address-form-three>
</form>
我用这两种情况更新了 stackblitz
注意:我想记得另一种方式,但我找不到链接:(
推荐阅读
- javascript - 具有可重新排序轴的渐进式渲染平行坐标d3.js V4?
- twitter-bootstrap - Bootstrap 表头组
- elasticsearch - Elasticsearch 别名和索引(相同的 id?)
- powershell - 追加文件的脚本
- javascript - 修改后保留原始数组顺序?
- excel - 仅当 lookup_value 包含值时,工作簿之间 VLOOKUP 的 Excel VBA 宏
- reactjs - 动态追加 JSX 组件作为特定 DOM 元素的子元素
- ruby - 查找嵌套哈希中的最大值
- python - python itertools groupby 返回空
- java - 在 StringSubstitutor 中支持大小写转换