Angular父子组件表单联动:子表单变更同步至父组件并双向绑定
实现Angular父子组件表单双向同步与嵌套整合
需求概述
我有一个包含两个子组件的父组件,需要子组件表单内容变更时实时同步到父组件,同时将嵌套表单作为Input传入子组件,实现双向联动。
初始代码结构
父组件初始表单:
profileForm = new FormGroup({ firstName: new FormControl(''), lastName: new FormControl(''), address: new FormGroup({}), });
子组件1现有代码:
@Output() onFormEmit = new EventEmitter<any>(); form = new FormGroup({ child1Key1: new FormControl(''), child1Key2: new FormControl(''), child1Key3: new FormControl(''), }); ngOnInit() { this.onFormEmit.emit(this.form); }
子组件2现有代码:
@Output() onFormEmit = new EventEmitter<any>(); form = new FormGroup({ child2Key4: new FormControl(''), child2Key5: new FormControl(''), }); ngOnInit() { this.onFormEmit.emit(this.form); }
期望最终父组件表单结构
profileForm = new FormGroup({ firstName: new FormControl(''), lastName: new FormControl(''), address: new FormGroup({ child1Key1: new FormControl(''), child1Key2: new FormControl(''), child1Key3: new FormControl(''), child2Key4: new FormControl(''), child2Key5: new FormControl(''), }), });
解决方案
方案一:直接共享父组件嵌套FormGroup(简单高效)
不再让子组件创建独立表单,而是直接接收父组件的address FormGroup,将子组件控件挂载到该组下,天然实现双向同步。
子组件1修改
import { Component, Input, OnInit } from '@angular/core'; import { FormGroup, FormControl } from '@angular/forms'; @Component({ selector: 'app-child1', templateUrl: './child1.component.html', }) export class Child1Component implements OnInit { @Input() parentFormGroup!: FormGroup; ngOnInit() { // 向父组件的address表单添加子组件控件 this.parentFormGroup.addControl('child1Key1', new FormControl('')); this.parentFormGroup.addControl('child1Key2', new FormControl('')); this.parentFormGroup.addControl('child1Key3', new FormControl('')); } }
子组件1模板:
<div [formGroup]="parentFormGroup"> <input formControlName="child1Key1" placeholder="子组件1字段1"> <input formControlName="child1Key2" placeholder="子组件1字段2"> <input formControlName="child1Key3" placeholder="子组件1字段3"> </div>
子组件2修改
import { Component, Input, OnInit } from '@angular/core'; import { FormGroup, FormControl } from '@angular/forms'; @Component({ selector: 'app-child2', templateUrl: './child2.component.html', }) export class Child2Component implements OnInit { @Input() parentFormGroup!: FormGroup; ngOnInit() { this.parentFormGroup.addControl('child2Key4', new FormControl('')); this.parentFormGroup.addControl('child2Key5', new FormControl('')); } }
子组件2模板:
<div [formGroup]="parentFormGroup"> <input formControlName="child2Key4" placeholder="子组件2字段4"> <input formControlName="child2Key5" placeholder="子组件2字段5"> </div>
父组件模板修改
将address FormGroup传递给子组件:
<form [formGroup]="profileForm"> <input formControlName="firstName" placeholder="名"> <input formControlName="lastName" placeholder="姓"> <div formGroupName="address"> <app-child1 [parentFormGroup]="profileForm.get('address') as FormGroup"></app-child1> <app-child2 [parentFormGroup]="profileForm.get('address') as FormGroup"></app-child2> </div> </form>
方案二:实现ControlValueAccessor(规范自定义表单控件)
如果需要子组件保持独立表单逻辑,可通过实现ControlValueAccessor接口,将子组件封装为自定义表单控件,无缝集成到父组件表单中。
子组件1示例
import { Component, forwardRef } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, FormGroup, FormControl } from '@angular/forms'; @Component({ selector: 'app-child1', templateUrl: './child1.component.html', providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => Child1Component), multi: true } ] }) export class Child1Component implements ControlValueAccessor { childForm = new FormGroup({ child1Key1: new FormControl(''), child1Key2: new FormControl(''), child1Key3: new FormControl('') }); onChange: any = () => {}; onTouched: any = () => {}; writeValue(value: any): void { if (value) { this.childForm.setValue(value, { emitEvent: false }); } } registerOnChange(fn: any): void { this.onChange = fn; this.childForm.valueChanges.subscribe(fn); } registerOnTouched(fn: any): void { this.onTouched = fn; } setDisabledState?(isDisabled: boolean): void { isDisabled ? this.childForm.disable() : this.childForm.enable(); } }
子组件1模板:
<div [formGroup]="childForm"> <input formControlName="child1Key1" placeholder="子组件1字段1"> <input formControlName="child1Key2" placeholder="子组件1字段2"> <input formControlName="child1Key3" placeholder="子组件1字段3"> </div>
父组件配置
profileForm = new FormGroup({ firstName: new FormControl(''), lastName: new FormControl(''), address: new FormGroup({ child1: new FormGroup({ child1Key1: new FormControl(''), child1Key2: new FormControl(''), child1Key3: new FormControl('') }), child2: new FormGroup({ child2Key4: new FormControl(''), child2Key5: new FormControl('') }) }), });
父组件模板:
<form [formGroup]="profileForm"> <input formControlName="firstName" placeholder="名"> <input formControlName="lastName" placeholder="姓"> <div formGroupName="address"> <app-child1 formControlName="child1"></app-child1> <app-child2 formControlName="child2"></app-child2> </div> </form>
内容的提问来源于stack exchange,提问作者paulotarcio
相关产品推荐
相关产品推荐

