You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Angular 8创建支持深层嵌套的递归动态表单

Angular 任意层级递归动态表单实现方案

问题核心成因

  • 初始调用递归模板未传递父分组参数,根层级字段渲染时读取空值触发UI崩溃
  • 原有普通字段模板强制绑定formGroupName,无父分组的根层级字段绑定该属性会抛出响应式表单错误
  • 递归上下文的父分组传递逻辑不符合Angular嵌套FormGroup的层级对应规则
  • 测试用JSON结构的group属性放置位置错误,需作为嵌套分组字段的自有属性,而非与普通字段平级

标准嵌套JSON结构示例

const filterFields = [
  {
    key: "common",
    title: "main fields",
    group: [
      {
        key: "createdAt",
        title: "Create Date",
        type: "date"
      },
      {
        key: "subGroup",
        title: "二级分组",
        group: [
          {
            key: "foo",
            title: "Foo",
            type: "select",
          },
          {
            key: "goo",
            title: "Goo",
            type: "input",
          },
          // 可无限新增嵌套分组
          {
            key: "thirdGroup",
            title: "三级分组",
            group: [
              {
                key: "bar",
                title: "Bar",
                type: "input"
              }
            ]
          }
        ]
      }
    ]
  }
]

修改后支持无限嵌套的模板代码

<form [formGroup]="filterForm" class="filter-form">
  <ng-template #recursiveList let-filterFields let-parentGroup="parentGroup">
    <ng-container *ngFor="let item of filterFields">
      <!-- 处理嵌套分组 -->
      <ng-container *ngIf="item.group; else defaultField">
          <p>{{item.key}}</p>
          <!-- 非根层级分组处理 -->
          <div [formGroupName]="item.key" *ngIf="parentGroup">
              <ng-container *ngTemplateOutlet="recursiveList; context:{ 
                $implicit: item.group, 
                parentGroup: item.key 
              }"></ng-container>
          </div>
          <!-- 根层级分组处理 -->
          <div [formGroup]="filterForm" *ngIf="!parentGroup">
            <ng-container *ngTemplateOutlet="recursiveList; context:{ 
              $implicit: item.group, 
              parentGroup: item.key 
            }"></ng-container>
          </div>
      </ng-container>
      <!-- 处理普通表单字段 -->
      <ng-template #defaultField>
        <div class="form-group">
          <!-- 有父分组的字段绑定 -->
          <input *ngIf="parentGroup" 
            [type]="item.type" 
            [formControlName]="item.key" 
            [placeholder]="item.title" 
            [name]="item.key" />
          <!-- 根层级字段绑定 -->
          <input *ngIf="!parentGroup" 
            [type]="item.type" 
            [formControl]="filterForm.get(item.key)" 
            [placeholder]="item.title" 
            [name]="item.key" />
        </div>
      </ng-template>
  </ng-container>
</ng-template>
<!-- 初始调用不传入parentGroup标识为根层级 -->
<ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit: filterFields }"></ng-container>
</form>

TS端配套修改说明

需要同步实现递归生成嵌套FormGroup的逻辑,不能仅生成扁平表单结构,参考代码:

import { FormBuilder, FormGroup } from '@angular/forms';

export class AppComponent {
  filterForm: FormGroup;
  filterFields = [] // 替换为你的JSON结构

  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    this.filterForm = this.fb.group({});
    this.buildFormGroup(this.filterFields, this.filterForm);
  }

  // 递归生成嵌套FormGroup
  buildFormGroup(fields: any[], parentGroup: FormGroup) {
    fields.forEach(item => {
      if (item.group) {
        const subGroup = this.fb.group({});
        parentGroup.addControl(item.key, subGroup);
        this.buildFormGroup(item.group, subGroup);
      } else {
        parentGroup.addControl(item.key, this.fb.control(''));
      }
    });
  }
}

以上修改完成后即可支持任意层级的递归嵌套表单,不会出现层级加深后UI崩溃的问题。

内容的提问来源于stack exchange,提问作者RoyBarOn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 04:39:02