简体   繁体   中英

Dynamically adding to a form array that is in another form array in angular2

I have the code of a components class below:

import {FormBuilder, FormGroup, Validators, FormControl, FormArray} from '@angular/forms'

...
form: FormGroup
constructor(private _fb: FormBuilder) { }

this.form = this._fb.group({
      name: ['', [Validators.required]],
      sortItem: this._fb.array([
        this.initSort(),
      ])
    });

initSort(){
    return this._fb.group({
      locationName: ['', [Validators.required]],
      locationItems: this._fb.array([
        this.initSortItems()
      ])
    })
  }

initSortItems(){
    return this._fb.group({
      itemName: ['', [Validators.required]],
      itemPicture: ['', []],
    })
  }

addSort(){
    const control = <FormArray>this.form.controls['sortItem'];
    control.push(this.initSort());
  }

addSortLocationItem(i?: number, t?: number){
    // add more locationItems to the sort. This is where I am stuck

// if tried the following with no avail  (<FormArray>this.form.get('sortItem').value[i].controls).push(this.initSortItems());

  }

I am trying to add more locationItems but what I've tried in the addSortLocationItem() method doesn't work. How can I access the form controls of the correct iteration of sortItem and add multiple locations items to that iteration?

This is my markup:

<div class="">
  <a (click)="addSort()" style="cursor: default">
    Add Sort Locations +
  </a>
</div>

<div formArrayName="sortItem">
  <div *ngFor="let sortLocation of form.controls.sortItem.controls; let i=index">
      <!-- address header, show remove button when more than one address available -->
      <div>
          <span>Location {{i + 1}}</span>
          <span *ngIf="form.controls.sortItem.controls.length > 1"
              (click)="removeAddress(i)">
          </span>
      </div>

      <div [formGroupName]="i">
          <!--name-->
          <div>
              <label>Location Name</label>
              <input type="text" formControlName="locationName">
              <!--display error message if street is not valid-->
              <small [hidden]="form.controls.sortItem.controls[i].controls.locationName.valid">
                  Street is required
              </small>
          </div>

          <div formArrayName="locationItems">
            <div *ngFor="let eachItem of form.controls.sortItem.controls[i].controls.locationItems.controls; let t=index">
                <!-- address header, show remove button when more than one address available -->
                <div class="">
                  <a (click)="addSortLocationItem(i,t)" style="cursor: default">
                    Add Items +
                  </a>
                </div>

                <div>
                    <span>Location Item {{t + 1}}</span>
                    <span *ngIf="form.controls.sortItem.controls[i].controls.locationItems.controls[t].length > 1"
                        (click)="removeAddress(t)">
                    </span>
                </div>

                <div [formGroupName]="t">
                    <!--name---->
                    <div>
                        <label>Item Name</label>
                        <input type="text" formControlName="itemName">
                        <!--display error message if street is not valid-->
                        <small [hidden]="form.controls.sortItem.controls[i].controls.locationItems.controls[t].controls.itemName.valid">
                            Name is required
                        </small>
                    </div>
                  </div>
              </div>
          </div>
      </div>
  </div>
</div>

Any help with this will be greatly appreciated.

If i is the index of the main control , so you can easily get with the following:

addSortLocationItem(i: number, t: number) {
  const control = this.sortItem.get(`${i}.locationItems`) as FormArray;
  control.push(this.initSortItems());
}

And, as an advice, I'd recommend you to create some variables in order to facilitate the readability of your code .

form: FormGroup;
name: FormControl;
sortItem: FormArray;

This:

<div *ngFor="let sortLocation of form.controls.sortItem.controls; let i=index">
...
<div *ngFor="let eachItem of form.controls.sortItem.controls[i].controls.locationItems.controls; let t=index">

Can be replaced by:

<div *ngFor="let sortLocation of sortItem.controls; let i = index">
...
<div *ngFor="let eachItem of sortLocation.get('locationItems').controls; let t = index">

The complete code:

import { Component, OnInit } from '@angular/core';
import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'

@Component({
  ...
})
export class BlaBlaComponent implements OnInit {

  form: FormGroup;
  name: FormControl;
  sortItem: FormArray;

  constructor(private readonly formBuilder: FormBuilder) { }

  ngOnInit(): void {  
    this.name = this.formBuilder.control('', [Validators.required]);
    this.sortItem = this.formBuilder.array([this.initSort()]);

    this.form = this.formBuilder.group({
      name: this.name,
      sortItem: this.sortItem
    });
  }

  initSort() {
    return this.formBuilder.group({
      locationName: ['', [Validators.required]],
      locationItems: this.formBuilder.array([
        this.initSortItems()
      ])
    })
  }

  initSortItems() {
    return this.formBuilder.group({
      itemName: ['', [Validators.required]],
      itemPicture: ['', []],
    })
  }

  addSort() {
    this.sortItem.push(this.initSort());
  }

  addSortLocationItem(i: number, t: number) {
    const control = this.sortItem.get(`${i}.locationItems`) as FormArray;
    control.push(this.initSortItems());
  }
 }

PS : I didn't test, let me know if I forgot something.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM