【问题标题】:Dynamically control the number of FormGroups with a FormArray使用 FormArray 动态控制 FormGroup 的数量
【发布时间】:2021-11-13 06:17:42
【问题描述】:

我正在尝试使用 FormArray 动态控制 FormGroup 的数量,以便设置 FormArray 长度。

myForm = this.fb.group({
  formGroupsToAdd: ['5'],
  formList: this.fb.array(this.getFormControls(5))
});

getFormControls(numberOfFormGroups: number) {
  const myArray = new Array(numberOfFormGroups);
  myArray.fill(this.fb.group({
    length: [''],
    width: [''],
    height: ['']
  }));
  return myArray;
}

我也有办法得到这个formList: FormArray

get unitList() {
  return this.myForm.get('formList') as FormArray;
}

但是,当我在此 FormArray 中向单个控件添加值时,它会更新 FormArray 中的所有 FormGroups。

<div formArrayName="formList">
  <div *ngFor="let unitForm of formList.controls; let i = index">
    <div [formGroup]="formList.controls[i]">
      <pre>{{formList.controls[i].value | json}}</pre>
      <pre>i = {{i}}</pre>
      <mat-form-field>
        <input matInput formControlName="length" />
      </mat-form-field>
      <mat-form-field>
        <input matInput formControlName="width" />
      </mat-form-field>
      <mat-form-field>
        <input matInput formControlName="height" />
      </mat-form-field>
    </div>
  </div>
</div>

所以我的formList.value 看起来像这样......

[
  {
    "length": "",
    "width": "asdf",
    "height": ""
  },
  {
    "length": "",
    "width": "asdf",
    "height": ""
  },
  {
    "length": "",
    "width": "asdf",
    "height": ""
  },
  {
    "length": "",
    "width": "asdf",
    "height": ""
  },
  {
    "length": "",
    "width": "asdf",
    "height": ""
  }
]

相反,我需要一个 FormGroup 来包含它自己独特的 FormControl 值。

我做错了什么?为什么 [formGroup]="formList.controls[i]" 不能通过为每个 formGroup 提供唯一标识符来满足我的需求?

编辑:我添加了一个堆栈闪电战来解决我的问题。
https://stackblitz.com/edit/angular-ivy-sa7pbb?file=src/app/app.component.html

【问题讨论】:

    标签: angular angular-reactive-forms formarray formgroups


    【解决方案1】:

    你应该像这样使用 [formGroupName]="idx​​"。

    <div formArrayName="formList">
      <div *ngFor="let unitForm of formList.controls; let i = index" [formGroupName]="i">
          <mat-form-field>
            <input matInput formControlName="length" />
          </mat-form-field>
          <mat-form-field>
            <input matInput formControlName="width" />
          </mat-form-field>
          <mat-form-field>
            <input matInput formControlName="height" />
          </mat-form-field>
      </div>
    </div>
    

    还有一些有用的功能:

    // Call init form on init
    ngOnInit(): void {
        this.initForm();
    }
    
    // init form here
    initForm() {
        this.myForm = this.fb.group({
          formList: this.fb.array([])
        });
    
        // Call this 5 times or any times you want to init rows.
        this.addItem();
    }
    
    // Add new item to make an addition button on UI
    addItem() {
        // You can enter input into newItem function to load data from API to make update/details screen.
        this.unitList.push(this.newItem(0, 0, 0));
    }
    
    // Your function to get fromList
    unitList() {
        return this.myForm.get('formList') as FormArray;
    }
    
    // new Item as a FormGroup to add into main form and it will auto render on UI
    newItem(length: number, width: number, height: number): FormGroup {
        const newGroup = this.fb.group({
          length: [length],
          width: [width],
          height: [height]
        })
        return newGroup;
    }
    
    // Clear all items to make a refresh/clean UI
    clearAllList() {
        this.unitList.clear();
    }
    
    // Remove item at index to make a delete button
    removeItem(index: number) {
        this.unitList.removeAt(idx);
    }
    

    更新: 修复 stackblitz 上的问题:https://stackblitz.com/edit/angular-ivy-rtmpwc?file=src/app/app.component.ts

    问题是myArray.fill,当您使用它时,它将使用 1 个引用变量来设置数组中的所有 5 个项目。因此,当您更改一项时,它将引用为 5 项

    getFormControls(numberOfFormGroups) {
        const myArray = new Array(numberOfFormGroups);
        myArray.fill(this.fb.group({
          length: [''],
          width: [''],
          height: ['']
        }));
        return myArray;
      }
    

    所以固定的功能应该是这样的。它将为 5 个项目创建 5 个引用。

    getFormControls(numberOfFormGroups) {
        const myArray = new Array();
        for (let i = 1; i <= numberOfFormGroups; i++) {
          let newItem = this.fb.group({ length: [''], width: [''], height: [''] });
          myArray.push(newItem);
        }
        return myArray;
      }
    

    【讨论】:

    • 我添加了一个 stackblitz 来说明我的问题。
    • 您是否尝试过此答案中提到的方法?
    • 好问题@MauricioGraciaGutierrez,是的。我做到了。它不起作用。
    • @MauricioGraciaGutierrez 我用我在 stackblitz 中的解决方案解决了他的问题,他说这不是问题。
    • @gh0st 我在这里更新了我的解决方案。
    【解决方案2】:

    您应该使用[formGroupName]="i" 而不是[formGroup]="formList.controls[i]"

    <div formArrayName="formList">
      <div *ngFor="let unitForm of formList.controls; let i = index">
        <div [formGroupName]="i">
          <pre>{{formList.controls[i].value | json}}</pre>
          <pre>i = {{i}}</pre>
          <mat-form-field>
            <input matInput formControlName="length" />
          </mat-form-field>
          <mat-form-field>
            <input matInput formControlName="width" />
          </mat-form-field>
          <mat-form-field>
            <input matInput formControlName="height" />
          </mat-form-field>
        </div>
      </div>
    </div>
    

    【讨论】:

    • 我添加了一个 stackblitz 来说明我的问题。
    • 您是否尝试过此答案中提到的方法?
    • 好问题@MauricioGraciaGutierrez,是的。我做到了。它不起作用。
    猜你喜欢
    • 2020-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-02
    • 1970-01-01
    • 2018-09-03
    • 2017-05-08
    • 2020-04-26
    相关资源
    最近更新 更多