从父组件更改嵌套表单字段值
Change nested form field value from parent component
假设我有一个实现 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)
});
现在我只想修补 addresForm 的 city
字段,所以我尝试了:
// 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 包含单个值,因此其他值将被重置。
那么如何在不重置其他字段值的情况下设置嵌套表单字段值呢?
换句话说,我们如何控制来自父级的嵌套表单组件字段,例如修补值或监听特定字段值的变化?
Stackblitz URL
庸俗,你没有一个formGroup里面的formGroup,你只有一个FormGroup和两个FormControl,最后一个存储一个object.
一般来说,当我们使用 FormGroup 时,我们可以采用两种方法
1.-在parent中定义完整的FormGroup,并将内部FormGroup
传递给children
this.productForm = new FormGroup({
date: new FormControl(null),
addressForm: new FormGroup({ //see that adressForm is a FormGroup
city: new FormControl()
postalCode: new FormControl(null)
})
});
我们的 child 是一个简单的组件 - 没有实现 controlValue 访问器
//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>
我们在parent
中使用
<form [formGroup]= "productForm">
<input formControlName="date">
<!--see that pass as @Input the formGroup-->
<address-form [addressForm]="productForm.get('addressForm')"> </address-form>
</form>
2.-创建一个自定义表单控件来管理 object {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()
}
并在parent中用作
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:自定义表单控件快速制作只为demo提案
Update 确实还有其他方法,我们可以,例如创建我们的表单
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 访问一个表单并创建一个类似
的表单
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;
});
}
而我们的 parent 组件:
<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
注意:我想记住另一种方式,但我找不到 link :(
假设我有一个实现 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)
});
现在我只想修补 addresForm 的 city
字段,所以我尝试了:
// 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 包含单个值,因此其他值将被重置。 那么如何在不重置其他字段值的情况下设置嵌套表单字段值呢?
换句话说,我们如何控制来自父级的嵌套表单组件字段,例如修补值或监听特定字段值的变化? Stackblitz URL
庸俗,你没有一个formGroup里面的formGroup,你只有一个FormGroup和两个FormControl,最后一个存储一个object.
一般来说,当我们使用 FormGroup 时,我们可以采用两种方法
1.-在parent中定义完整的FormGroup,并将内部FormGroup
传递给childrenthis.productForm = new FormGroup({
date: new FormControl(null),
addressForm: new FormGroup({ //see that adressForm is a FormGroup
city: new FormControl()
postalCode: new FormControl(null)
})
});
我们的 child 是一个简单的组件 - 没有实现 controlValue 访问器
//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>
我们在parent
中使用<form [formGroup]= "productForm">
<input formControlName="date">
<!--see that pass as @Input the formGroup-->
<address-form [addressForm]="productForm.get('addressForm')"> </address-form>
</form>
2.-创建一个自定义表单控件来管理 object {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()
}
并在parent中用作
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:自定义表单控件快速制作只为demo提案
Update 确实还有其他方法,我们可以,例如创建我们的表单
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 访问一个表单并创建一个类似
的表单 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;
});
}
而我们的 parent 组件:
<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
注意:我想记住另一种方式,但我找不到 link :(