如何在Angular响应式表单中根据元数据动态设置不同input输入类型
解决方案
你需要调整现有代码的递归模板传参逻辑,把表单元数据同步传入递归上下文,再根据元数据字段做条件渲染即可,修改步骤如下:
步骤1:调整组件类逻辑
首先要保证你的响应式表单结构和元数据结构完全对齐,新增递归构建表单的方法,同时把元数据暴露为模板可访问的公共属性:
import { Component } from '@angular/core'; import { FormBuilder, FormGroup, FormArray } from '@angular/forms'; // 你的元数据定义 export const data: TreeItem = { 'element': [{ 'name':'age', 'label':'Age', 'fieldType':'select', 'type': '', 'element': [ { 'name':'dateOfBirth', 'label':'Date Of Birth', 'fieldType':'date', 'type': '', 'element': [] } ] }] }; @Component({ selector: 'app-tree-form', templateUrl: './tree-form.component.html' }) export class TreeFormComponent { public testForm: FormGroup; // 元数据暴露为公共属性,模板可直接访问 public metaData = data; constructor(private fb: FormBuilder) { this.testForm = this.fb.group({ element: this.fb.array(this.buildFormGroupList(this.metaData.element)) }) } // 递归构建嵌套表单组 private buildFormGroupList(metaItems: any[]): FormGroup[] { return metaItems.map(item => { return this.fb.group({ // 用元数据的name作为表单控件名,和字段一一对应 [item.name]: [''], type: [''], element: this.fb.array( item.element.length ? this.buildFormGroupList(item.element) : [] ) }) }) } onSubmit() { console.log(this.testForm.value); } }
步骤2:修改模板递归逻辑
给递归模板新增metaItems入参,遍历表单控件的同时取对应位置的元数据做条件判断:
<form class="tree" [formGroup]="testForm" (ngSubmit)="onSubmit()"> <ng-template #recursiveList let-controls let-prefix="prefix" let-metaItems="metaItems"> <ng-container *ngFor="let item of controls; let i = index"> <!-- 取当前控件对应的元数据项 --> <ng-container *ngIf="metaItems[i] as currentMeta"> <div class="tree-item" [formGroup]="testForm.get(prefix + i)"> <!-- 按fieldType条件渲染对应输入控件 --> <input *ngIf="currentMeta.fieldType === 'date'" type="date" [formControlName]="currentMeta.name" > <input *ngIf="currentMeta.fieldType === 'input'" type="text" [formControlName]="currentMeta.name" > <select *ngIf="currentMeta.fieldType === 'select'" [formControlName]="currentMeta.name" > <!-- 可根据业务需求扩展option选项 --> <option value="">请选择</option> </select> <!-- 原有的type输入框,不需要可以直接删除 --> <input type="text" formControlName="type"> </div> <!-- 嵌套子项递归调用,传入子级元数据 --> <div class="sub-tree" *ngIf="item.get('element')?.controls?.length"> <ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit: item.get('element').controls, prefix: prefix + i + '.element.', metaItems: currentMeta.element }" ></ng-container> </div> </ng-container> </ng-container> </ng-template> <!-- 初始调用递归模板,传入根级元数据 --> <ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit: testForm.get('element').controls, prefix: 'element.', metaItems: metaData.element }" ></ng-container> </form>
关键注意事项
- 注意你元数据里的类型字段是
fieldType,条件判断时不要写错成你示例里的inputType - 动态的
formControlName需要用方括号绑定[formControlName]="currentMeta.name",不能直接写死字符串 - 递归传参时必须同步传入对应层级的元数据,保证每一层控件和元数据的索引一一对应
内容的提问来源于stack exchange,提问作者RoyBarOn
相关产品推荐
相关产品推荐

