如何在 Angular 9 ReactiveForm 中获取嵌套的 FormArray 控件

Ala*_*ine 4 typescript angular angular-reactive-forms formarray


编辑

由于上面 Chellappan 的回答,问题的第一部分得到了解决,但我遇到了其他问题,这让我做了一个 stackblitz,可以在这里找到: https ://stackblitz.com/edit/angular-ivy-bzh3dh

问题是我无法正确检索从表单中选择的产品列表,因为它们全部输出:

  "courses": [
    {
      "courseName": "Dessert",
      "products": [
        {
          "product": true
        },
        {
          "product": false
        },
        {
          "product": null
        }
      ]
Run Code Online (Sandbox Code Playgroud)

我不知道如何能够检索类似的内容:

  "courses": [
    {
      "courseName": "Dessert",
      "products": [
        {
          "Crumble aux pommes": true
        },
        {
          "Mousse au chocolat maison": false
        },
        {
          "Riz au lait": false
        }
      ]
Run Code Online (Sandbox Code Playgroud)

第二个问题是我的复选框的标签不是独立的。如果我添加新的“课程”并选择一些产品,其他课程中所有复选框的标签也会更改。

在此输入图像描述

我希望我的帖子不要太乱,我不会经常在 Stack Overflow 上编辑消息

编辑结束


我有一个带有嵌套表单数组的反应式表单来描述包含多个课程的菜单,每个课程包含多个产品,但我不知道如何使其工作。我的实际问题是我无法检索第二级控件。

这是菜单的 json 结构:

{
  "name": "",
  "description": "",
  "price": "",
  "courses": [
    {
      "courseName": "",
      "products": [
        {
          "product": ""
        }
      ]
    }
  ]
}

Run Code Online (Sandbox Code Playgroud)

我以这个项目为例:

深层嵌套反应形式

为了便于阅读,这是我的简化表格:

  "courses": [
    {
      "courseName": "Dessert",
      "products": [
        {
          "product": true
        },
        {
          "product": false
        },
        {
          "product": null
        }
      ]
Run Code Online (Sandbox Code Playgroud)

这是我在 TS 中的表单初始化:

  "courses": [
    {
      "courseName": "Dessert",
      "products": [
        {
          "Crumble aux pommes": true
        },
        {
          "Mousse au chocolat maison": false
        },
        {
          "Riz au lait": false
        }
      ]
Run Code Online (Sandbox Code Playgroud)

如果我像这样离开后端,则会出现错误:

Cannot read property 'controls' of undefined at MenuEditComponent.getProducts
Run Code Online (Sandbox Code Playgroud)

所以我的“产品”FormArray 未初始化。如果我做 :

{
  "name": "",
  "description": "",
  "price": "",
  "courses": [
    {
      "courseName": "",
      "products": [
        {
          "product": ""
        }
      ]
    }
  ]
}

Run Code Online (Sandbox Code Playgroud)

我不再有错误,但我无法访问产品 formControls。如果我尝试:

    <form [formGroup]="menuForm" (ngSubmit)="onSubmit(menuForm)">

        <div class="form-group">
          <input
            class="form-control"
            formControlName="name"
            type="text">
        </div>
        <div class="form-group">
          <textarea
            class="form-control"
            formControlName="description"></textarea>
        </div>
        <div class="col-md-3 form-group">
          <input
            class="form-control"
            formControlName="price"
            type="number">
        </div>
      </div>
      <div class="row col-md-12">
        <button class="btn btn-outline-dark" type="button" (click)="onAddCourse()">
          Add course
        </button>
      </div>

      <div class="row" formArrayName="courses">
        <div *ngFor="let course of getCourses(menuForm); let i = index"
            [formGroupName]="i">

          <div class="...">
              <select
                class="form-control"
                formControlName="courseName">
                <option *ngFor="let course of courses">{{course.name}}</option>
              </select>

              <button type="button" class="mt-2 btn btn-outline-dark" (click)="onLoadProducts(i)">
                Load Products // <- will load products that have course Name selected form the input 'courseName'above
              </button>

              <div class="row" formArrayName="products">
                <div class="col-md-12"
                     *ngFor="let product of getProducts(menuForm); let j = index"
                      [formGroupName]="j">
                  <input class="form-check-input" type="checkbox" id="product{{i}}-{{j}}" 
                   formControlName="product"/>
                  <label class="form-check-label" for="product{{i}}-{{j}}">product</label>
                </div>
              </div>
          </div>
        </div>
      </div>

      <br>
      <div class="row col-md-12">
        <button class="btn btn-success mr-1" type="submit" [disabled]="!menuForm.valid">{{buttonSubmitLabel}}</button>
      </div>
    </form>
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么 ?为什么我的“产品”FormArray 未初始化?

非常感谢你的帮助 !

mua*_*f80 6

我查看了你的 stackblitz,并对其进行了修改并使其正常工作。您不需要将 formControlName 与您的产品绑定,因为您不是从前端 UI 设置它们,而只是选择它们。added我在类中添加了一个名为的字段ProductModel,然后我刚刚实现了change复选框的事件来将其标记为真或假。

您还可以看到我如何设置产品的值。当您点击Load Products按钮时,您将添加空白FormGroup,但您还应该product使用产品数据在其中设置控件。您可以在代码中看到我是如何在 LoadProducts 方法中执行此操作的

之后,您可以在产品循环中看到我如何获取产品字段。该循环实际上为我们提供了 FormGroup,我们必须从中获取产品字段值

这是正在做这项工作的 stackblitz。

https://stackblitz.com/edit/angular-ivy-ohwv1v

特别可以注意这部分

if (this.productsByCategory) {
  this.productsByCategory.forEach(
  (product) => {
    const productForm: FormGroup = this.initProduct();
    productForm.controls.product.setValue(product);
      control.push(productForm);
    });
}
Run Code Online (Sandbox Code Playgroud)

创建productFormGroup后,您还应该在其中设置产品。喜欢productForm.controls.product.setValue(product);

然后在前端你可以看到

<div *ngFor="let p of getProducts(course); let j = index" [formGroupName]="j">
  <input type="checkbox" id="product{{i}}-{{j}}" [value]="p.value.product.added" (change)="p.value.product.added = !p.value.product.added"/>
  <label  for="product{{i}}-{{j}}">{{p.value.product.name}}</label>
</div>
Run Code Online (Sandbox Code Playgroud)

您应该将值绑定到产品的添加属性,并且名称也应该显示在产品对象的标签内。

希望这将帮助您进一步前进。

第二个问题是我的复选框的标签不是独立的。如果我添加新的“课程”并选择一些产品,其他课程中所有复选框的标签也会更改。

以上问题已解决

我不知道如何能够检索类似的内容:

而不是productName: true/false您拥有可用的整个产品对象,并且该added字段将标记其是否checked/unchecked

  • 令人惊奇的是您花费了这么多时间并给了我一个完整且正确的解决方案!明天我会深入研究它,因为它今天真的杀了我!但我发现它工作得很好!我真的不知道该怎么感谢你!太完美了!多谢 ! (3认同)