Search code examples
angularangular-reactive-forms

Adding dynamic controls in an Angular form fails


I am spending to much time on something that should be simpler and I don't get it where is the mistake. I just try to add some dynamic inputs controls to a form but it fails with error Cannot find control with name: '0'. I put an example here: Stackblitz demo

<form [formGroup]="form"  class="top15x2" autocomplete="off">

<div class="w-100  text-start">
<button type='button' mat-button (click)="onAddDependent()" class="button-submit" style="width:150px">+ Add Dependent</button>
</div>


<div
  *ngFor="let dependentsGroup of this.dependentsControls().controls let i=index"
  [formGroupName]="i">
  
  <div class="d-flex flex-row w-100 justify-content-start gap20">
    <div class="col-2">
      <mat-form-field class="w-100">
        <mat-label>Name </mat-label>
        <input matInput formControlName="dependentNameControl" />
        <mat-error *ngIf="formControls['dependentNameControl'].invalid">
          {{formControls['dependentNameControl'].hasError('minlength') ? "Min 2
          chars":""}}
          {{formControls['dependentNameControl'].hasError('maxlength') ? "Max 50
          chars":""}}
        </mat-error>
      </mat-form-field>
    </div>
  </div>
</div>


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

/** @title Basic datepicker */
@Component({
  selector: 'example',
  templateUrl: 'example.html',
})
export class Example {
  public form!: FormGroup;

  constructor(private formBuilder: FormBuilder) {}

  ngOnInit(): void {
    this.form = this.formBuilder.group({
      dependentsControls: new FormArray([]),
    });
  } //ngOnInit

  get formControls() {
    return this.form.controls;
  }

  dependentsControls(): FormArray {
    return <FormArray>this.form.controls['dependentsControls'];
  }

  public createDependent() {
    return this.formBuilder.group({
      dependentNameControl: new FormControl<string | undefined>('', [
        Validators.minLength(2),
        Validators.maxLength(50),
      ]),
    });
  }

  public onAddDependent(): void {
    this.dependentsControls().push(this.createDependent());
    console.log(this.dependentsControls().controls);
  }
}

/**  Copyright 2022 Google LLC. All Rights Reserved.
    Use of this source code is governed by an MIT-style license that
    can be found in the LICENSE file at https://angular.io/license */

Solution

  • You need to add formArrayName, and also change controls reference to each dynamic group:

    Try this:

     <div formArrayName="dependentsControls">
        <div
          *ngFor="let dependentsGroup of this.dependentsControls().controls let i=index"
          [formGroupName]="i"
        >
         ...
                <mat-error
                  *ngIf="dependentsGroup.get('dependentNameControl')?.invalid"
                >
                  {{dependentsGroup.get('dependentNameControl')?.hasError('minlength')
                  ? "Min 2 chars":""}}
                  {{dependentsGroup.get('dependentNameControl')?.hasError('maxlength')
                  ? "Max 50 chars":""}}
                </mat-error>
              </mat-form-field>
            </div>
          </div>
        </div>
      </div>
    

    Stackblitz