如何在 FormGroup 中动态生成 FormControls?

How can I generate FormControls dynamically inside a FormGroup?

我从数据库接收到一个对象,其中包含一些具有以下格式的元素:

info = [{
    idcentro: "8227",
    namecentro: "Centro Paris", 
    address: "C/ Paris, 127",
    dias: [
      {
        dia: "0",
        horafinal: "06:00",
        horainicio: "17:00",
        salas: [
          {
            id: 0,
            nombre: "sala 1",
            intervalos: [
                ["09:00", "12:30", "10"],
                ["13:00", "21:30", "20"]
            ]
          }
        ]
      },
      {
        dia: "1",
        horafinal: "09:00",
        horainicio: "16:30",
        salas: [
          {
            id: 0,
            nombre: "sala 1",
            intervalos: [
                ["09:00", "12:30", "10"]
            ]
          },
          {
            id: 1,
            nombre: "sala 2",
            intervalos: [
                ["09:00", "20:30", "20"]
            ]
          }
        ]
      },
      {
        dia: "2",
        horafinal: "09:00",
        horainicio: "20:30",
        salas: [
          {
            id: 0,
            nombre: "sala 1",
            intervalos: [
                ["09:00", "12:30", "10"],
                ["12:45", "18:30", "15"]
            ]
          },
          {
            id: 1,
            nombre: "sala 2",
            intervalos: [
                ["09:00", "20:30", "20"]
            ]
          }
        ]
      }
    ]
  }];

为了使用这些“dias”数组并包含输入以在用户需要时修改每个值,我手动创建了一个 FormGroup,其中包含那些日子中的每一天的 formControl(真实对象最多包含 8 个天)。

    this.openingHoursForm = new FormGroup({
      day0OpeningTime: new FormControl(""),
      day0ClosingTime: new FormControl(""),
      day1OpeningTime: new FormControl(""),
      day1ClosingTime: new FormControl(""),
      day2OpeningTime: new FormControl(""),
      day2ClosingTime: new FormControl(""),
      day3OpeningTime: new FormControl(""),
      day3ClosingTime: new FormControl(""),
      day4OpeningTime: new FormControl(""),
      day4ClosingTime: new FormControl(""),
      day5OpeningTime: new FormControl(""),
      day5ClosingTime: new FormControl(""),
      day6OpeningTime: new FormControl(""),
      day6ClosingTime: new FormControl(""),
      day7OpeningTime: new FormControl(""),
      day7ClosingTime: new FormControl(""),
      day8OpeningTime: new FormControl(""),
      day8ClosingTime: new FormControl("")
    });

然后,在 HTML 中,我为每个 formControlNames 创建了两个输入:

<div class="dayOpeningHours" title="">
  <div>Day 0</div>
   <div class="opens">
     <label for="">De:
       <input class="form-control" type="time" formControlName="day0OpeningTime" name="day0OpeningTime">
     </label>
   </div>
   <div class="closes">
     <label for="">A:
       <input class="form-control" formControlName="day0ClosingTime" name="day0ClosingTime">
     </label>
   </div>
</div>

如您所见,这变得非常难以维护。我试图通过遍历 'dias' 数组的每个“dia”来动态创建标记(在 html 中)和 formControlNames(在 ts 中),但我没有取得任何成就。

有没有办法在同一个 formGroup 中生成 HTML 和那些 Form Controls 的声明?我一直在阅读有关 FormArray 和 AbstractControl 的内容,但我无法真正理解如何将其应用到我的代码中。

有人可以帮助我或给我一些提示来找到正确的文档吗?

谢谢

更好的选择是使用 FormArray。您还可以从 @angular/forms

注入 FormBuilder

见下文

constructor (private fb: FormBuilder) { }
diasForm = this.fb.group({
  openingHours: this.fb.array([])
})
get openingHours (): FormArray {
  return this.diasForm.get('openingHours') as FormArray;
}

下一个任务是创建表单 假设我们有 dias 作为数组

dias = [
      {
        dia: "0",
        horafinal: "06:00",
        horainicio: "17:00",
      },
      {
        dia: "1",
        horafinal: "06:00",
        horainicio: "17:00",
      },
      ...
]

为简单起见,我删除了其他属性 在ngOnInit中我们可以设置我们表单的值

ngOnInit() {
  this.dias.forEach(dia => {
    this.openingHours.push(
      this.fb.group({
        horafinal: [dia.horafinal, []],
        horainicio: [dia.horainicio, []]
      })
    )
  })
}

在Html

<form [formGroup]='diasForm'>
  <div formArrayName='openingHours'>
    <div *ngFor='let item of openingHours.controls; let i = index' 
       [formGroupName]='i'>
         <input formControlName='horafinal' />
         <input formControlName='horainicio' />
    </div>
  </div>
</form>

以上应该符合我们formGroup的结构

diasForm( [formGroup] ) ---> openingHours(formArray) ---> i ( [formGroup] ) ---> horafinal(formControl)

请参阅this demo on stackblitz

这样你就可以有一个动态的天数

它是一个大而复杂的对象,但是控制 json 对象的“方式”总是相同的:简单的属性是 FormControl,数组是 FormArrays,我们使用 FormGroup 对控件进行分组。

这么细心,做四个函数来创建表单

  createForm(data: any = null) {
    data = data || {idcentro: null,namecentro: null,address: null,dias: null};
    return new FormGroup({
      idcentro: new FormControl(data.idcentro),
      namecentro: new FormControl(data.namecentro),
      address: new FormControl(data.address),
      dias: new FormArray(
        data.dias ? data.dias.map(x => this.createFormDias(x)) : []
      )
    });
  }
  createFormDias(data: any = null) {
    data = data || {dia: null,horafinal: null,horainicio: null,salas: null};
    return new FormGroup({
      dia: new FormControl(data.dia),
      horafinal: new FormControl(data.horafinal),
      horainicio: new FormControl(data.horainicio),
      salas: new FormArray(
        data.salas ? data.salas.map(x => this.createFormSalas(x)) : []
      )
    });
  }
createFormSalas(data: any = null) {
    data = data || { id: null, nombre: null, intervalos: null };
    return new FormGroup({
      id: new FormControl(data.id),
      nombre: new FormControl(data.nombre),
      intervalos:new FormArray(
        data.intervalos?this.createFormIntervalos(data.intervalos):[])
    });
  }
  createFormIntervalos(data:any=null)
  {
    return data.map(x=>new FormArray(x.map(y=>new FormControl(y))))
  }

还有四个函数来获取formArrays

  get diasArray()
  {
    return this.form.get('dias') as FormArray
  }
  getSalas(index)
  {
    return this.diasArray.at(index).get('salas') as FormArray
  }
  getIntervalos(index1,index2)
  {
    return this.getSalas(index1).at(index2).get('intervalos') as FormArray
  }
  getHoras(index1,index2,index3)
  {
    return this.getIntervalos(index1,index2).at(index3) as FormArray
  }

要在 .html 中进行控制,您需要考虑何时 FormArray 是 FormGroups 的 FormArray 以及何时是 FormControls 的 FormArray

<form [formGroup]="form">
  <div>idcentro:<input formControlName="idcentro" /></div>
  <div>namecentro:<input formControlName="namecentro" /></div>
  <div>address:<input formControlName="address" /></div>
  <div formArrayName="dias">
    <div
      *ngFor="let grDias of diasArray.controls;let i=index"
      [formGroupName]="i"
    >
      <div>dia:<input formControlName="dia" /></div>
      <div>horafinal:<input formControlName="horafinal" /></div>
      <div>horainicio:<input formControlName="horainicio" /></div>
      <div formArrayName="salas">
        <div
          *ngFor="let grSalas of getSalas(i).controls;let j=index"
          [formGroupName]="j"
        >
          <div>id:<input formControlName="id" /></div>
          <div>nombre:<input formControlName="nombre" /></div>
          <div formArrayName="intervalos">
            <div
              *ngFor="let grIntervalos of getIntervalos(i,j).controls;let k=index"
            >
              <div [formArrayName]="k">
                <div *ngFor="let grHoras of getHoras(i,j,k).controls;let m=index">
                  <input [formControlName]="m">
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</form>

ugly stackblitz

看到我们使用的FormGroup的FormArray

<div formGroupName="nameOfArray">
  <div *ngFor="let group of formArray.controls;let i=index" [formGroupName]="i">
     ..here..
     <input formControlName="controlName">
  </div>
</div>

还有一个 FormControl 的 FormGroup

<div formGroupName="nameOfArray">
  <div *ngFor="let group of formArray.controls;let i=index" >
     <input [formControlName]="i">
  </div>
</div>