Reactive-forms in Angular is very powerful to handle changes in value, check the statuses, and perform validations on a form-field in particular form because of supporting FormGroup, FormControl, and FormArray.
But sometimes it is very difficult to organize the hierarchy and inside the FormGroup and FormArray. It might be the case that we want to add FormControl dynamically to FormArray after completion of some operations like the completion of an API call and also want to remove it.
This article explains how we can add and remove checkboxes dynamically to and from FormArray and also making a custom validator that checks if at least one checkbox is checked or not. Let’s start.
It is not the case that you can only add FormControl to FormArray. You can also add entirely new FormGroup to the FormArray.
For this article we will use component named DynamicFormComponent which renders our Form. I am assuming that you already have an working Angular project and a component to render your Form.
import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, FormArray } from '@angular/forms'; @Component({ selector: 'app-dynamic-form', templateUrl: './dynamic-form.component.html', styleUrls: ['./dynamic-form.component.css'] }) export class DynamicFormComponent implements OnInit { demoForm: FormGroup; arrayItems: { id: number; title: string; }[]; constructor(private _formBuilder: FormBuilder) { this.demoForm = this._formBuilder.group({ demoArray: this._formBuilder.array([]) }); } ngOnInit() { this.arrayItems = []; } }
<form [formGroup]="demoForm"> <div formArrayName="demoArray" *ngFor="let arrayItem of arrayItems; let i=index"> <input [id]="arrayItem.id" type="checkbox" [formControl]="demoArray[i]"> <label [for]="arrayItem.id" class="array-item-title"> {{arrayItem.title}}</label> </div> </form>
... ... export class DynamicFormComponent implements OnInit { ... ... get demoArray() { return this.demoForm.get('demoArray') as FormArray; } addItem(item) { this.arrayItems.push(item); this.demoArray.push(this._formBuilder.control(false)); } removeItem() { this.arrayItems.pop(); this.demoArray.removeAt(this.demoArray.length - 1); } ... ... }
import { FormBuilder, FormGroup, FormArray, ValidatorFn } from '@angular/forms'; ... ... export class DynamicFormComponent implements OnInit { constructor(private _formBuilder: FormBuilder) { this.demoForm = this._formBuilder.group({ demoArray: this._formBuilder.array( [],this.minSelectedCheckboxes() ) }); } ... ... minSelectedCheckboxes(): ValidatorFn { const validator: ValidatorFn = (formArray: FormArray) => { const selectedCount = formArray.controls .map(control => control.value) .reduce((prev, next) => next ? prev + next : prev, 0); return selectedCount >= 1 ? null : { notSelected: true }; }; return validator; } }
That’s it. As we added and removed a FormControl, same way you can also add and remove entire FormGroup to FormArray and can have a custom validator to validate that FormGroup.
Thank you.