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

问题描述 投票:1回答:1

编辑

问题的第一部分由于上面的Chellappan的回答而得以解决,但是我遇到了其他问题,这使我进行了堆炸弹攻击,可以在这里找到:https://stackblitz.com/edit/angular-ivy-bzh3dh

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

  "courses": [
    {
      "courseName": "Dessert",
      "products": [
        {
          "product": true
        },
        {
          "product": false
        },
        {
          "product": null
        }
      ]

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

  "courses": [
    {
      "courseName": "Dessert",
      "products": [
        {
          "Crumble aux pommes": true
        },
        {
          "Mousse au chocolat maison": false
        },
        {
          "Riz au lait": false
        }
      ]

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

enter image description here

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

编辑结束


我有一个带有嵌套表格Array的反应式表格,用于描述包含几门课程的菜单而且每门课程都包含几种产品,但是我不知道如何使它起作用。我的实际问题是我无法检索第二级控件。

这是菜单的json结构:

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

我以这个项目为例:

Deep nested reactive form

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

    <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>

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

export class MenuEditComponent implements OnInit {

  menuForm: FormGroup;
  menu: MenuModel;
  categories: CategoryModel[];
...

  constructor(private router: Router,
              private route: ActivatedRoute,
              private productService: ProductService,
              private menuService: MenuService) { }

  ngOnInit(): void {
    this.productService.getCategories().subscribe(
      result => {
        this.categories = result;
      },
      error => {
        console.log(error);
        this.categories = [];
      });
    this.initForm();
  }

  initForm() {
    this.menuForm = new FormGroup({
      name: new FormControl('', [Validators.required, Validators.maxLength(100)]),
      description: new FormControl('', Validators.maxLength(255)),
      price: new FormControl('', [Validators.required, Validators.min(0)]),
      courses: new FormArray([
        this.initCourse(),
      ])
    });
  }

  initCourse() {
    return new FormGroup({
      courseName: new FormControl(''),
      products: new FormArray([
        this.initProduct()
      ])
    });
  }

  initProduct() {
    return new FormGroup({
      product: new FormControl('')
    });
  }

  getCourses(form) {
    return form.controls.courses.controls;
  }

  getProducts(form) {
    return form.controls.products.controls;
  }

  onAddCourse() {
    const control = this.menuForm.get('courses') as FormArray;
    control.push(this.initCourse());
  }

  onLoadProducts(i: number) {
    console.log(this.menuForm.controls.courses);
    const courseControl = this.menuForm.get('courses') as FormArray;
    const course = courseControl.at(i).get('courseName').value;
    console.log(course);
    const products: ProductModel[] = this.mapProducts.get(course);
    console.log(products);
    const productControl = this.menuForm.get('courses').get[i].get('products') as FormArray;

  onSubmit(menuForm: FormGroup) {
    ...
  }

...
}

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

Cannot read property 'controls' of undefined at MenuEditComponent.getProducts

因此,我的“产品” FormArray未初始化。如果我这样做:

  getProducts(form) {
    return form.controls.products?.controls;
  }

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

  onLoadProducts(i: number) {
    const courseControl = this.menuForm.get('courses') as FormArray;
    const course = courseControl.at(i).get('courseName').value;
    const products: ProductModel[] = this.mapProducts.get(course);
    const productControl = this.menuForm.get('courses').get[i].get('products') as FormArray;
    //On the last line i get a 'Cannot read property 'get' of undefined'
...
}

我在做什么错?为什么我的“产品” FormArray没有初始化?

非常感谢您的帮助!

angular typescript angular-reactive-forms formarray
1个回答
0
投票

课程是formGroup的数组,而formGroup产品内部是另一个formArray,因此您必须将单课程formGroup传递给getProducts方法。

© www.soinside.com 2019 - 2024. All rights reserved.