Angular 动态形式的形式阵列

Angular 动态形式的形式阵列,angular,typescript,angular-reactive-forms,formarray,form-control,Angular,Typescript,Angular Reactive Forms,Formarray,Form Control,我已经实现了一个stackblitz,您可以使用一些配置创建一个动态表单。在使用格式阵列之前,一切正常。有什么想法?基本上,配置文件中可以有许多不同类型的字段。例如,复选框,文本,编号选择等。在某些情况下,您应该有一个更复杂的结构,因此您应该有一个格式数组。在这场闪电战中,我试图代表正在发生的事情 因此,当我找到一个数组类型时,我将创建一个FormArray,而不是一个简单的FormControl,这是我的字段列表 public fields: any[] = [ { t

我已经实现了一个stackblitz,您可以使用一些配置创建一个动态表单。在使用
格式阵列之前,一切正常。有什么想法?基本上,配置文件中可以有许多不同类型的字段。例如,
复选框
文本
编号
选择
等。在某些情况下,您应该有一个更复杂的结构,因此您应该有一个
格式数组
。在这场闪电战中,我试图代表正在发生的事情

因此,当我找到一个
数组
类型时,我将创建一个FormArray,而不是一个简单的
FormControl
,这是我的字段列表

 public fields: any[] = [
    {
      type: "text",
      name: "firstName",
      label: "First Name",
      required: true
    },
    {
      type: "text",
      name: "lastName",
      label: "Last Name",
      required: true
    },
    {
      type: "text",
      name: "email",
      label: "Email",
      required: true
    },
    {
      type: "text",
      name: "description",
      label: "Description",
      required: true,
      multiLine: true
    },
    {
      type: "dropdown",
      name: "country",
      label: "Country",
      value: "in",
      required: true,
      options: [{ value: "in", label: "India" }, { value: "us", label: "USA" }]
    },
    {
      type: "array",
      name: "users",
      label: "Users",
      structure: "users.json"
    }
  ];
这是我的动态表单生成器组件

export class DynamicFormBuilderComponent implements OnInit {
  @Output() onSubmit = new EventEmitter();
  @Input() fields: any[] = [];
  form: FormGroup;
  allDatas: any;
  constructor() {}

  ngOnInit() {
    let fieldsCtrls = {};
    this.allDatas = getData();
    for (let f of this.fields) {
      if (f.type != "array") {
        fieldsCtrls[f.name] = new FormControl(
          this.allDatas[f.name] || "",
          Validators.required
        );
      } else {
        fieldsCtrls[f.name] = new FormArray([
          new FormControl(this.allDatas[f.name] || "", Validators.required)
        ]);
      }
    }
    this.form = new FormGroup(fieldsCtrls);
  }
}
如您所见,我从allDatas(如果存在)中设置了一个值,并使用FormControls和FormArray创建了FormGroup。但是当我生成
arraybox
时,我有错误。这是显示FormArray控件的arraybox组件:

import { HttpClient } from "@angular/common/http";
import { Component, Input, OnInit } from "@angular/core";
import { FormGroup } from "@angular/forms";
import { ConfigService } from "../../config.service";

@Component({
  selector: "arraybox",
  template: `
    <div [formGroup]="form">
      <div formArrayName="{{ field.name }}">
        <div
          *ngFor="let obj of arrayFileds; index as idx"
          [formGroupName]="idx"
        >
          <input
            attr.type="{{ obj.type }}"
            class="form-control"
            placeholder="{{ obj.name }}"
            id="{{ obj.name }}"
            name="{{ obj.name }}"
            formControlName="{{ idx }}"
          />
        </div>
      </div>
    </div>
  `
})
export class ArrayBoxComponent implements OnInit {
  @Input() field: any = {};
  @Input() form: FormGroup;
  arrayFileds: any = [];

  get isValid() {
    return this.form.controls[this.field.name].valid;
  }
  get isDirty() {
    return this.form.controls[this.field.name].dirty;
  }

  constructor(private config: ConfigService) {}

  ngOnInit(): void {
    this.arrayFileds = this.config.getData(this.field.structure);
    console.log(this.arrayFileds);
  }
}
控制台中的错误有:

ERROR
Error: Cannot find control with path: 'users -> 0 -> 0'
ERROR
Error: Cannot find control with path: 'users -> 1'
我真的不知道这里出了什么问题。如何使用FormArray在此表单中显示字段及其值


注意。若我使用http解析json,stackblitz会给我一个错误,所以现在我直接使用json的导入。基本上,本例中未使用此.field.structure(但应使用)。

检查此
stackblitz
示例:-


希望它对你有用

好吧,干得不错,但是你需要改变一些事情来实现你想要的

  • 您需要更改初始化表单数组的方式。您已经在
    FormArray
    中命名了控件,因此需要将
    FormGroup
    推送到
    FormArray
    中:
  • 上面的代码基本上生成
    FormGroup
    ,其对象键为
    FormControls

  • 您需要更改
    ArrayBox
    组件模板,如下所示:

  • 还请注意,已将
    idx
    变量移动到父循环。

    这并不是我想要的。此示例仅创建FormControl。不是为了感谢你的回答。你的例子部分是有效的。我的意思是,没关系,我想怎么做就怎么做,但结果只有一个。我只能看到{userName:“第二次测试”,userEmail:“secondEmail@test.com“}而不是第一个。你能确认吗?@End.Game我现在注意到了。将更新问题和stackblitz。
    ERROR
    Error: Cannot find control with path: 'users -> 0 -> 0'
    ERROR
    Error: Cannot find control with path: 'users -> 1'
    
     for (let f of this.fields) {
          if (f.type != "array") {
            fieldsCtrls[f.name] = new FormControl(
              this.allDatas[f.name] || "",
              Validators.required
            );
          } else { // changed part
            fieldsCtrls[f.name] = new FormArray([
              ...this.allDatas[f.name].map(
                r =>
                  new FormGroup(
                    Object.entries(r).reduce((acc, [k, v]) => {
                      acc[k] = new FormControl(v || "", Validators.required);
                      return acc;
                    }, {})
                  )
              )
            ]);
          }
    
     <input
                attr.type="{{ obj.type }}"
                class="form-control"
                placeholder="{{ obj.name }}"
                id="{{ obj.name }}"
                name="{{ obj.name }}"
                formControlName="{{ obj.name }}"
              />
    
       <div [formGroup]="form">
          <div formArrayName="{{ field.name }}">
            <div *ngFor="let frm of formArray.controls; index as idx">
              <div formGroupName="{{ idx }}">
                <div *ngFor="let obj of arrayFileds;">
                  <input
                    attr.type="{{ obj.type }}"
                    class="form-control"
                    placeholder="{{ obj.name }}"
                    id="{{ obj.name }}"
                    name="{{ obj.name }}"
                    formControlName="{{ obj.name }}"
                  />
                </div>
                <hr />
              </div>
            </div>
          </div>
        </div>