Andrew Howard
Andrew Howard

Reputation: 3072

Angular 2 - Form builder looping through an array and then an inner array

I have the following JSON which I wish to map out to a form:

{
  "lineItemId": 0,
  "count": 0,
  "fixtures": [
    {
      "fixtureId": 0,
      "fixtureName": "string",
      "total": 0,
      "completed": 0,
      "guestDetails": [
        {
          "id": 0,
          "forename": "string",
          "surname": "string",
          "email": "string",
          "telephone": "string",
          "specialInstructions": "string",
          "completed": true,
          "dietaryRequirements": [
            {
              "id": 0,
              "name": "string",
              "isRequired": true
            }
          ]
        }
      ]
    }
  ]
}

I then have the following working typescript which maps it out to formbuilder:

this.myForm = this.fBuilder.group({
   guestDetailsForm: this.fBuilder.array([])
});

this.httpService.getGuestDetails(this.eventId, this.passedIdValue)
   .subscribe(data => {
      this.fixturesArray = data.fixtures;
      console.log(this.fixturesArray);
      this.fixturesArray.forEach(fixturesArrayElement => {
          this.guestDetailsArray = fixturesArrayElement.guestDetails;
          this.guestDetailsArray.forEach(element => {
            (<FormArray>this.myForm.get('guestDetailsForm')).push(this.fBuilder.group({
            id: [element.id],
            forename: [element.forename],
            surname: [element.surname, Validators.required],
            email: [element.email],
            telephone: [element.telephone],
            dietaryRequirements: [element.dietaryRequirements]
          }));
      });
});
},
   error => alert(error),
   () => console.log(""));

I can list out the forename, surname, email etc all fine but it won't display the text fields for the "dietaryRequirements" data in the following template. I assume it's to do with my inner *ngFor loop but nothing seems to work. Any help? :)

<div class="generalForm" formArrayName="guestDetailsForm">
  <div *ngFor="let guest of myForm.controls.guestDetailsForm.controls; let i=index" [ngClass]="{'guestForm show' : viewingGuestId == i, 'guestForm hide' : viewingGuestId != i}">
     <div [formGroupName]="i">
        <input type="hidden" formControlName="id" />
        <ol>
           <li class="inputQuestion">
             <label>Forename</label>
             <input type="text" formControlName="forename" />
            </li>
            <li class="inputQuestion">
              <label>Surname</label>
              <input type="text" formControlName="surname" />
              <div [hidden]="myForm.controls.guestDetailsForm.controls[i].controls.surname.valid" class="inlineError">Required
              </div>
            </li>
            <li class="inputQuestion">
                <label>Email</label>
                <input type="text" formControlName="email" />
            </li>
            <li class="inputQuestion">
                <label>Telephone</label>
                <input type="text" formControlName="telephone" />
            </li>
            <li class="dietaryRequirementsQuestion" formArrayName="dietaryRequirements">

               <div *ngFor="let meals of myForm.controls.guestDetailsForm.controls[i].controls.dietaryRequirements; let x=index">
                  <div [formGroupName]="x">
                     <input type="text" formControlName="name" />
                  </div>
               </div>
             </li>
          </ol>
        </div>
      </div>
    </div>

Upvotes: 1

Views: 3502

Answers (1)

yurzui
yurzui

Reputation: 214017

I would create FormArray instead of just array for dietaryRequirements

buildFormArrayOfGroupsFromArr(arr) {
  return this.fBuilder.array(arr.map(x => this.fBuilder.group(x)));
}
...

dietaryRequirements: this.buildFormArrayOfGroupsFromArr(element.dietaryRequirements)

After that you write the following html:

<div *ngFor="let meals of myForm.controls.guestDetailsForm.controls[i].controls.dietaryRequirements.controls; let x=index">
  <div [formArrayName]="x">
    <input type="text" formControlName="name" />
  </div>
</div>

You can also have a look at Plunker Example

Upvotes: 5

Related Questions