Search code examples
angularforms

Dynamically add items to a checklist (which is a form)


I want to create a form for adding items to a checklist, where the minimum of items is 1, but the maximum is unknown. To achieve that, I tried to dynamically add formControls to a form. I´ve several issues with that:

  1. when I initally insert a value for first item and press the + button, no new field for second item is rendered
  2. when I press the + plus button a second time a new field is rendered incompletly (means material style is not applied)
  3. additionally I push the strings into a string[], but this has just empty strings

I prepared a stackblitz-demo for you, thx for any help https://stackblitz.com/edit/stackblitz-starters-ayejpy?file=src%2Fmain.ts


Solution

  • You can use formarray to deal with dynamic array elements

    // add a formarray to form
    checklist: this.formBuilder.array([]),
    
    // add a getter for a formarray
    get checklist() {
      return this.formGroup.get('checklist') as FormArray;
    }
    
    //write a fn to add/remove elements to formarray
    modifyCheckList(index: number, mode: boolean) {
      const formArray = this.checklist;
      const value = index > 0 ? formArray.at(index).value : null;
      if (mode) {
        formArray.push(new UntypedFormControl(value, [Validators.required]));
      } else {
        formArray.removeAt(index);
      }
    }
    
    // add first array item checklist
    this.modifyCheckList(0, true); 
    
    

    modify your template to accept these new elements

    <form [formGroup]="formGroup" (ngSubmit)="onSubmit()">
    ...
    <ng-container formArrayName="checklist">
      <div *ngFor="let checklistPoint of checklist.controls; let i = index; let isFirst=first; let isLast = last;">
        <mat-form-field appearance="fill">
          <mat-label>Checklist-ToDo {{ i + 1 }}</mat-label>
          <input matInput [formControlName]="i" required />
        </mat-form-field>
        <button mat-mini-fab color="primary" type="button" (click)="modifyCheckList(i, true)" [disabled]="!isLast">
          +
        </button>
        <button mat-mini-fab color="warn" type="button" (click)="modifyCheckList(i, false)" [disabled]="isLast">
          -
        </button>
      </div>
    </ng-container>
    
    {{formGroup.value|json}}
    ...
    </form>
    

    Updated Stackblitz for your reference https://stackblitz.com/edit/stackblitz-starters-dfbxwe