Search code examples
angulartypescriptionic-frameworkangular-reactive-forms

Angular Ionic Reactive Form: Form Not Displaying


I'm facing an issue with my Angular/Ionic form where it's not displaying the form controls correctly on the web. Currently, I'm trying to implement a dynamic form where users can input the number of groups and students for each year. However, when I view the form in the browser, I can only see the "Submit" button, but none of the form fields are visible.

Here's my code:

<form [formGroup]="inputForm" (ngSubmit)="onSubmit()">
  <ion-list formArrayName="years">
    <ion-item-group *ngFor="let year of getYearsControls(); let yearIndex = index">
      <ion-header>
        <ion-label>Year {{ yearIndex + 1 }}</ion-label>
      </ion-header>
      <ion-item>
        <ion-label>Number of groups</ion-label>
        <ion-input type="number" formControlName="numGroups" placeholder="Number of groups"></ion-input>
      </ion-item>
      <ion-item *ngFor="let group of getGroupsControls(yearIndex); let groupIndex = index">
        <ion-label>Number of students</ion-label>
        <ion-input type="number" formControlName={{groupIndex}} placeholder="Number of students"></ion-input>
        <ion-button (click)="removeStudents(yearIndex, groupIndex)" color="danger" fill="clear">
          Remove Students
        </ion-button>
      </ion-item>
      <ion-item-divider>
        <ion-button (click)="addStudents(yearIndex)" expand="block">Add Number of Students</ion-button>
      </ion-item-divider>
    </ion-item-group>
  </ion-list>
  <ion-button type="submit" expand="block">Submit</ion-button>
</form>

I've set up a FormGroup containing a FormArray for the years, and within each year, there's a FormArray for groups and individual form controls for the number of groups and students.

I've double-checked my component logic and template bindings, but I can't seem to figure out why the form controls are not rendering within the Ionic components.

Any help or suggestions on how to resolve this issue would be greatly appreciated. Thank you!

export class TestFormComponent  implements OnInit {
  @Output() formDataSubmitted = new EventEmitter<any>();
  inputForm!: FormGroup;

  constructor(private formBuilder: FormBuilder) {
    this.inputForm = this.formBuilder.group({
      years: this.formBuilder.array([])
    });
    this.addYearsControls();
    console.log('inputForm initialized:', this.inputForm);
  }

  ngOnInit() {}


  addYearsControls() {
    const yearsFormArray = this.inputForm.get('years') as FormArray;
    for (let i = 0; i < 5; i++) {
      yearsFormArray.push(this.createYearGroup());
    }
  }

  createYearGroup(): FormGroup {
    return this.formBuilder.group({
      numGroups: ['', Validators.required],
      groups: this.formBuilder.array([])
    });
  }

  addStudents(yearIndex: number) {
    const yearGroupsArray = (this.inputForm.get(`years.${yearIndex}.groups`) as FormArray);
    yearGroupsArray.push(this.createGroupControl());
  }

  removeStudents(yearIndex: number, groupIndex: number) {
    const yearGroupsArray = (this.inputForm.get(`years.${yearIndex}.groups`) as FormArray);
    yearGroupsArray.removeAt(groupIndex);
  }

  createGroupControl(): FormControl {
    return new FormControl('');
  }

  onSubmit() {
    this.formDataSubmitted.emit(this.inputForm.value);
    console.log(this.inputForm.value);
  }

  getYearsControls() {
    return ((this.inputForm.get('years') as FormArray).controls);
  }

  getGroupsControls(yearIndex: number) {
    return ((this.inputForm.get(`years.${yearIndex}.groups`) as FormArray).controls);
  }
}

Solution

    1. You miss out on the [formGroupName]="yearIndex" when iterating the year form groups with getYearsControls().

    2. You miss out on the formArrayName="groups" before generating each group FormControl via getGroupsControls(yearIndex).

    <form [formGroup]="inputForm" (ngSubmit)="onSubmit()">
      <ion-list formArrayName="years">
        <ion-item-group
          *ngFor="let year of getYearsControls(); let yearIndex = index"
          [formGroupName]="yearIndex"
        >
          <ion-header>
            <ion-label>Year {{ yearIndex + 1 }}</ion-label>
          </ion-header>
          <ion-item>
            <ion-label>Number of groups</ion-label>
            <ion-input
              type="number"
              formControlName="numGroups"
              placeholder="Number of groups"
            ></ion-input>
          </ion-item>
          <ng-container formArrayName="groups">
            <ion-item
              *ngFor="
                let group of getGroupsControls(yearIndex);
                let groupIndex = index
              "
            >
              <ion-label>Number of students</ion-label>
              <ion-input
                type="number"
                formControlName="{{ groupIndex }}"
                placeholder="Number of students"
              ></ion-input>
              <ion-button
                (click)="removeStudents(yearIndex, groupIndex)"
                color="danger"
                fill="clear"
              >
                Remove Students
              </ion-button>
            </ion-item>
            <ion-item-divider>
              <ion-button (click)="addStudents(yearIndex)" expand="block"
                >Add Number of Students</ion-button
              >
            </ion-item-divider>
          </ng-container>
        </ion-item-group>
      </ion-list>
      <ion-button type="submit" expand="block">Submit</ion-button>
    </form>
    
    

    Demo @ StackBlitz