1

I have a nested form created for an ionic project, in which I have formGroups that contain formArray, and each formArray has one or more formGroups, itself. The process of saving data works great. I can have as many formArrays with as many formGroups as I like.

My problem is when I am trying to populate the form with a saved data. I cannot add correctly the data inside the formArrays.

This is my edit script:

import { Component } from '@angular/core';
import { FormBuilder, FormControl, FormArray, FormGroup, Validators } from '@angular/forms';
import { NavController, NavParams } from 'ionic-angular';
import { Todos } from '../../providers/todos';
import { HomePage } from '../home/home';
import { Patient } from '../../interfaces/patient.interface';

@Component({
  selector: 'page-edit',
  templateUrl: 'edit.html'
})
export class EditPage {

  patient: any;
  patientDate: any;
  editTodoForm: FormGroup;
  submitted: boolean;
  events: any[] = [];

  constructor(public navCtrl: NavController, public todoService: Todos, public navParams: NavParams, public formBuilder: FormBuilder) {
    this.patient = this.navParams.data;
    this.patientDate = new Date(this.patient.date).toISOString();
    this.editTodoForm = formBuilder.group({
      _id: [this.patient._id],
      _rev: [this.patient._rev],
      firstName: [this.patient.firstName, Validators.compose([Validators.pattern('[a-zA-Z ]*'), Validators.required])],
      date: [this.patientDate],
      botoxes: this.formBuilder.array([]),
      acids: this.formBuilder.array([])
    });
    this.subcribeToFormChanges();
    this.addBotox();
    this.addAcid();

  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad EditPage');
    this.editTodoForm.setValue(this.patient);
  }

  initBotox() {
    return this.formBuilder.group({
      botoxDate: [''],
      botoxTypes: this.formBuilder.array([
        this.formBuilder.group({
          botoxType: [''],
          botoxZone: [''],
          botoxUnit: ['']
        })
      ])
    });
  }

  addBotox() {
    const control = <FormArray>this.editTodoForm.controls['botoxes'];
    const botoxCtrl = this.initBotox();
    if(this.patient.botoxes) {
      this.patient.botoxes.forEach(botox => {
        control.push(botoxCtrl);
      })
    } else {
      control.push(botoxCtrl);
    }

  }

  removeBotox(i: number) {
    const control = <FormArray>this.editTodoForm.controls['botoxes'];
    control.removeAt(i);
  }

  initAcid() {
    return this.formBuilder.group({
      acidDate: [''],
      acidTypes: this.formBuilder.array([
        this.formBuilder.group({
          acidType: [''],
          acidZone: [''],
          acidUnit: ['']
        })
      ])
    });
  }

  addAcid() {
    const control = <FormArray>this.editTodoForm.controls['acids'];
    const acidCtrl = this.initAcid();

    control.push(acidCtrl);
  }

  removeAcid(i: number) {
    const control = <FormArray>this.editTodoForm.controls['acids'];
    control.removeAt(i);
  }

  subcribeToFormChanges() {
        const myFormStatusChanges$ = this.editTodoForm.statusChanges;
        const myFormValueChanges$ = this.editTodoForm.valueChanges;

        myFormStatusChanges$.subscribe(x => this.events.push({ event: 'STATUS_CHANGED', object: x }));
        myFormValueChanges$.subscribe(x => this.events.push({ event: 'VALUE_CHANGED', object: x }));
    }

  updateTodo(model: Patient, isValid: boolean) {
    this.submitted = true;
    this.todoService.updateTodo(this.editTodoForm.value);
    this.navCtrl.setRoot(HomePage);
  }

}

This is the edit html:

<ion-header no-border>
  <ion-navbar color="primary">
    <ion-title>Editeaza pacient</ion-title>
  </ion-navbar>
</ion-header>


<ion-content padding>

  <form [formGroup]="editTodoForm" novalidate>
    <div [hidden]="editTodoForm.controls.firstName.valid || (editTodoForm.controls.firstName.pristine && !submitted)" class="error-notification">
      Pacientul trebuie sa aiba cel putin un nume si un prenume
    </div>

    <ion-card>
      <ion-card-header>
        Date personale
      </ion-card-header>
      <ion-list padding>
        <ion-item>
          <ion-label stacked>Prenume pacient</ion-label>
          <ion-input type="text" formControlName="firstName"></ion-input>
        </ion-item>
        <ion-item>
          <ion-label stacked>Dată activitate</ion-label>
          <ion-datetime displayFormat="DD MMMM YYYY" pickerFormat="DD MMMM YYYY" formControlName="date"
          monthNames="ianuaie, februarie, martie, aprilie, mai, iunie, iulie, august, septembrie, octombrie, noiembrie, decembrie"></ion-datetime>
        </ion-item>
      </ion-list>
    </ion-card>

    <ion-card>
      <ion-card-header>
        Tratamente botox
      </ion-card-header>
      <ion-list padding>
        <ion-card formArrayName="botoxes">
          <div *ngFor="let botox of editTodoForm.controls.botoxes.controls; let i=index">
            <p class="card-heading">
              <span>Tratament cu botox {{i + 1}}</span>
              <button ion-button icon-only *ngIf="editTodoForm.controls.botoxes.controls.length > 1" (click)="removeBotox(i)" class="right-button remove-button">
      <ion-icon name="trash"></ion-icon>
    </button>
            </p>
            <div [formGroupName]="i">
              <botoxInputs [group]="editTodoForm.controls.botoxes.controls[i]"></botoxInputs>
            </div>
          </div>
        </ion-card>
        <button (click)="addBotox()" ion-button icon-left>
          <ion-icon name="add"></ion-icon>
          Adauga tratament cu botox
        </button>
      </ion-list>
    </ion-card>

    <ion-card>
      <ion-card-header>
        Tratamente acid hialuronic
      </ion-card-header>
      <ion-list padding>
        <ion-card formArrayName="acids">
          <div *ngFor="let acid of editTodoForm.controls.acids.controls; let i=index">
            <p class="card-heading">
              <span>Tratament cu acid hialuronic {{i + 1}}</span>
              <button ion-button icon-only *ngIf="editTodoForm.controls.acids.controls.length > 1" (click)="removeAcid(i)" class="right-button remove-button">
      <ion-icon name="trash"></ion-icon>
    </button>
            </p>
            <div [formGroupName]="i">
              <acidInputs [group]="editTodoForm.controls.acids.controls[i]"></acidInputs>
            </div>
          </div>
        </ion-card>
        <button (click)="addAcid()" ion-button icon-left>
          <ion-icon name="add"></ion-icon>
          Adauga tratament cu acid hialuronic
        </button>
      </ion-list>
    </ion-card>

    <div padding>
      <button ion-button color="primary" block type="submit" (click)="createPatient(editTodoForm, editTodoForm.valid)">Salveaza date pacient</button>
    </div>


  </form>


</ion-content>

And this is an example of a saved JSON I am trying to add back to the form:

{
    "firstName": "Ionescu Ion",
    "date": "2017-02-01T00:00:00.000Z",
    "botoxes": [{
        "botoxDate": "2017-02-01",
        "botoxTypes": [{
            "botoxType": "Xeomin 100UI",
            "botoxZone": ["Frunte", "Crow feet", "Sprânceană"],
            "botoxUnit": "111"
        }, {
            "botoxType": "Azzalure 50UI",
            "botoxZone": ["Glabelar", "Intersprincenos", "Frunte"],
            "botoxUnit": "222"
        }]
    }],
    "acids": [{
        "acidDate": "2017-02-01",
        "acidTypes": [{
            "acidType": "Juvederm Volift",
            "acidZone": ["Periocular", "Tâmple"],
            "acidUnit": "0.5 ml"
        }]
    }],
    "_id": "0A418E81-CFD0-545B-B8DB-A326CECFC5F1",
    "_rev": "3-f2914e24db5fac42930dba548f418cbd"
}

My problem is that I can get only on e botoxType displayed of the two botoxTypes.

I would really appreciate any help

2
  • Updated the question with code. Please let me know if any other code is needed. Commented Mar 2, 2017 at 12:47
  • Hi, we (at work) have been working on that topic and I gave a proper answer you may want to check here stackoverflow.com/a/55457210/2398593 :) Commented Apr 1, 2019 at 14:14

1 Answer 1

2

For anyone having the same issues as I had. This is how I changed my edit script to set initial values properly on formArrays:

import { Component } from '@angular/core';
import { FormBuilder, FormArray, FormGroup, Validators } from '@angular/forms';
import { NavController, NavParams } from 'ionic-angular';
import { Todos } from '../../providers/todos';
import { HomePage } from '../home/home';
import { Patient } from '../../interfaces/patient.interface';

@Component({
  selector: 'page-edit',
  templateUrl: 'edit.html'
})
export class EditPage {

  patient: any;
  editTodoForm: FormGroup;
  submitted: boolean;
  events: any[] = [];

  constructor(public navCtrl: NavController, public todoService: Todos, public navParams: NavParams, public formBuilder: FormBuilder) {
    this.patient = this.navParams.data;
    this.editTodoForm = formBuilder.group({
      _id: [this.patient._id],
      _rev: [this.patient._rev],
      firstName: ['', Validators.compose([Validators.pattern('[a-zA-Z ]*'), Validators.required])],
      date: [''],
      botoxes: this.formBuilder.array([]),
      acids: this.formBuilder.array([])
    });
    this.subcribeToFormChanges();
    if(this.patient.botoxes.length > 0) {
      this.patient.botoxes.forEach(botox => {
        let btys = botox.botoxTypes.length;
        this.addBotox(btys);
      });
    } else {
      this.addBotox(1);
    }
    if(this.patient.acids.length > 0) {
      this.patient.acids.forEach(acid => {
        let atys = acid.acidTypes.length;
        this.addAcid(atys);
      });
    } else {
      this.addAcid(1);
    }

  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad EditPage');
    const value: Patient = this.navParams.data;
    (<FormGroup>this.editTodoForm).patchValue(value, { onlySelf: true });
  }

  initBotox(number) {
    return this.formBuilder.group({
      botoxDate: [''],
      botoxTypes: this.addBotoxTypes(number)
    });
  }

  initBotoxTypes() {
      return this.formBuilder.group({
        botoxType: [''],
        botoxZone: [''],
        botoxUnit: ['']
      });
  }


  addBotoxTypes(number) {
    let bts = new FormArray([]);
    for(let i = 0; i < number; i++) {
      bts.push(this.initBotoxTypes())
    }
    return bts;
  }

  addBotox(number) {
    const control = <FormArray>this.editTodoForm.controls['botoxes'];
    const botoxCtrl = this.initBotox(number);
    control.push(botoxCtrl);
  }

  removeBotox(i: number) {
    const control = <FormArray>this.editTodoForm.controls['botoxes'];
    control.removeAt(i);
  }

  initAcid(number) {
    return this.formBuilder.group({
      acidDate: [''],
      acidTypes: this.addAcidTypes(number)
    });
  }

  initAcidTypes() {
      return this.formBuilder.group({
        acidType: [''],
        acidZone: [''],
        acidUnit: ['']
      });
  }


  addAcidTypes(number) {
    let acs = new FormArray([]);
    for(let i = 0; i < number; i++) {
      acs.push(this.initAcidTypes())
    }
    return acs;
  }

  addAcid(number) {
    const control = <FormArray>this.editTodoForm.controls['acids'];
    const acidCtrl = this.initAcid(number);

    control.push(acidCtrl);
  }

  removeAcid(i: number) {
    const control = <FormArray>this.editTodoForm.controls['acids'];
    control.removeAt(i);
  }

  subcribeToFormChanges() {
        const myFormStatusChanges$ = this.editTodoForm.statusChanges;
        const myFormValueChanges$ = this.editTodoForm.valueChanges;

        myFormStatusChanges$.subscribe(x => this.events.push({ event: 'STATUS_CHANGED', object: x }));
        myFormValueChanges$.subscribe(x => this.events.push({ event: 'VALUE_CHANGED', object: x }));
    }

  updateTodo(model: Patient, isValid: boolean) {
    this.submitted = true;
    this.todoService.updateTodo(this.editTodoForm.value);
    this.navCtrl.setRoot(HomePage);
  }

}
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.