如何在Angular中通过valueChanges追踪动态添加的嵌套表单值变化
问题
我通过遍历对象数组向父表单动态添加FormControl,希望在ngOnInit方法中为根FormGroup添加valueChanges来追踪这些动态添加控件的变化。但目前代码中valueChanges仅能追踪表单中已存在的输入控件变化,无法追踪动态添加元素的变化。
当前在动态添加的控件中输入内容时,console.log不会输出日志,仅在静态FormControl中输入时才会输出。若在动态添加内容后为dynamicForm单独添加valueChanges,可以追踪动态内容的变化,但我想避免这种方式,仅通过在ngOnInit中为根FormGroup添加valueChanges来实现。
我的代码如下:
import 'zone.js'; import { Component, inject, OnInit, signal, WritableSignal, } from '@angular/core'; import { bootstrapApplication } from '@angular/platform-browser'; import { FormBuilder, FormsModule, ReactiveFormsModule, FormControl, } from '@angular/forms'; @Component({ selector: 'app-root', standalone: true, imports: [ReactiveFormsModule, FormsModule], template: ` <form [formGroup] = 'employeeForm'> <input formControlName='orgName'> @if(showEmpInfo().length > 0){ <div formGroupName="dynamicContent"> @for(emp of showEmpInfo();track emp){ <input type = 'text' [formControlName] = "emp.formControlName"> } </div> } <button (click) ='addControl()'>Add</button> </form> `, }) export class App implements OnInit { fb = inject(FormBuilder); showEmpInfo: WritableSignal < any[] > = signal([]); employeeForm = this.fb.group({ orgName: [''], dynamicContent: this.fb.group({}), }); formObj = [{ type: 'text', formControlName: 'employee', }, { type: 'text', formControlName: 'empId', }, ]; ngOnInit() { this.employeeForm.valueChanges.subscribe((val) => console.log(val)); } addControl() { const dynamicForm = this.fb.group({}); this.formObj.forEach((elem) => { dynamicForm.addControl(elem.formControlName, new FormControl('', [])); }); this.employeeForm.controls['dynamicContent'] = dynamicForm; this.showEmpInfo.set(this.formObj); } } bootstrapApplication(App);
解决方案
问题出在你直接替换了dynamicContent这个FormGroup实例,而不是在原有的FormGroup上添加控件。Angular的valueChanges是基于初始的控件订阅关系,替换整个子FormGroup会导致根表单的订阅无法感知到新控件的变化。
正确的做法是保留初始的dynamicContent子FormGroup,直接向它添加新控件,而不是创建新的FormGroup替换它:
- 移除创建新
dynamicForm的代码 - 获取根表单中已有的
dynamicContent子FormGroup - 遍历
formObj,直接向这个已存在的子FormGroup添加控件(可选先清空已有控件,避免重复添加)
修改后的addControl方法如下:
addControl() { // 获取已有的dynamicContent子FormGroup const dynamicContentGroup = this.employeeForm.get('dynamicContent') as FormGroup; // 清空已有控件(避免重复添加,可选) Object.keys(dynamicContentGroup.controls).forEach(key => { dynamicContentGroup.removeControl(key); }); // 向已有组添加控件 this.formObj.forEach((elem) => { dynamicContentGroup.addControl(elem.formControlName, new FormControl('', [])); }); this.showEmpInfo.set(this.formObj); }
这样修改后,根表单的valueChanges就能正常追踪到动态添加控件的变化了——因为我们没有替换子FormGroup,只是修改了它内部的控件,根表单的订阅会自动感知到子组内部的变化。
内容的提问来源于stack exchange,提问作者brk
相关产品推荐
相关产品推荐

