How to validate that at least one checkbox should be selected? How to validate that at least one checkbox should be selected? angular angular

How to validate that at least one checkbox should be selected?


The accepted answer abuses stuff to use in a way they are not meant to be. With reactive forms the best, easiest and probably right way is to use a FormGroup that holds your grouped checkboxes and create a validator to check if at least one(or more) checkbox is checked within that group.

To do so just create another FormGroup inside your existing FormGroup and attach a validator to it:

form = new FormGroup({    // ...more form controls...    myCheckboxGroup: new FormGroup({      myCheckbox1: new FormControl(false),      myCheckbox2: new FormControl(false),      myCheckbox3: new FormControl(false),    }, requireCheckboxesToBeCheckedValidator()),    // ...more form controls...  });

And here is the validator. I made it so you can even use it to check if at least X checkboxes are checked, e.g. requireCheckboxesToBeCheckedValidator(2):

import { FormGroup, ValidatorFn } from '@angular/forms';export function requireCheckboxesToBeCheckedValidator(minRequired = 1): ValidatorFn {  return function validate (formGroup: FormGroup) {    let checked = 0;    Object.keys(formGroup.controls).forEach(key => {      const control = formGroup.controls[key];      if (control.value === true) {        checked ++;      }    });    if (checked < minRequired) {      return {        requireCheckboxesToBeChecked: true,      };    }    return null;  };}

In your template don't forget to add the directive 'formGroupName' to wrap your checkboxes. But don't worry, the compiler will remind you with an error-message if you forget. You can then check if the checkbox-group is valid the same way you do on FormControl's:

<ng-container [formGroup]="form">   <!-- ...more form controls... -->   <div class="form-group" formGroupName="myCheckboxGroup">      <div class="custom-control custom-checkbox">        <input type="checkbox" class="custom-control-input" formControlName="myCheckbox1" id="myCheckbox1">        <label class="custom-control-label" for="myCheckbox1">Check</label>      </div>      <div class="custom-control custom-checkbox">        <input type="checkbox" class="custom-control-input" formControlName="myCheckbox2" id="myCheckbox2">        <label class="custom-control-label" for="myCheckbox2">At least</label>      </div>      <div class="custom-control custom-checkbox">        <input type="checkbox" class="custom-control-input" formControlName="myCheckbox3" id="myCheckbox3">        <label class="custom-control-label" for="myCheckbox3">One</label>      </div>      <div class="invalid-feedback" *ngIf="form.controls['myCheckboxGroup'].errors && form.controls['myCheckboxGroup'].errors.requireCheckboxesToBeChecked">At least one checkbox is required to check</div>    </div>    <!-- ...more form controls... -->  </ng-container>

*This template is very static. Of course you could create it dynamically by using an additional array that holds the the form-data(key of FormControl, label, required, etc.) and create the template automatically by use of ngFor.

Please don't abuse hidden FormControl's like in the accepted answer. A FormControl is not meant to store data like id, label, help-text etc. and doesnt even have a name/key. All this, and much more, should be stored separate, e.g. by a regular array of objects. A FormControl only holds an input-value and provides all this cool state's and functions.

I created a working example you can play with: https://stackblitz.com/edit/angular-at-least-one-checkbox-checked


consider creating a FormGroup which contains your check-box group and bind the group's checked value to a hidden formcontrol with a required validator.

Assume that you have three check boxes

items = [  {key: 'item1', text: 'value1'},      // checkbox1 (label: value1)  {key: 'item2', text: 'value2'},      // checkbox2 (label: value2)  {key: 'item3', text: 'value3'},      // checkbox3 (label: value3)];

Step1: define FormArray for your check boxes

let checkboxGroup = new FormArray(this.items.map(item => new FormGroup({  id: new FormControl(item.key),      // id of checkbox(only use its value and won't show in html)  text: new FormControl(item.text),   // text of checkbox(show its value as checkbox's label)  checkbox: new FormControl(false)    // checkbox itself})));

*easy to show via ngFor

Step2: create a hidden required formControl to keep status of checkbox group

let hiddenControl = new FormControl(this.mapItems(checkboxGroup.value), Validators.required);// update checkbox group's value to hidden formcontrolcheckboxGroup.valueChanges.subscribe((v) => {  hiddenControl.setValue(this.mapItems(v));});

we only care about hidden control's required validate status and won't show this hidden control in html.

Step3: create final form group contains below checkbox group and hidden formControl

this.form = new FormGroup({  items: checkboxGroup,  selectedItems: hiddenControl});

Html Template:

<form [formGroup]="form">  <div [formArrayName]="'items'" [class.invalid]="!form.controls.selectedItems.valid">    <div *ngFor="let control of form.controls.items.controls; let i = index;" [formGroup]="control">      <input type="checkbox" formControlName="checkbox" id="{{ control.controls.id.value }}">      <label attr.for="{{ control.controls.id.value }}">{{ control.controls.text.value }}</label>    </div>  </div>  <div [class.invalid]="!form.controls.selectedItems.valid" *ngIf="!form.controls.selectedItems.valid">    checkbox group is required!  </div>  <hr>  <pre>{{form.controls.selectedItems.value | json}}</pre></form>

refer this demo.


I had the same problem and this is the solution I ended up using with Angular 6 FormGroup because I had few checkboxes.

HTMLNote: I'm using Angular Material for styling, change as needed.

<form [formGroup]="form">  <mat-checkbox formControlName="checkbox1">First Checkbox</mat-checkbox>  <mat-checkbox formControlName="checkbox2">Second Checkbox</mat-checkbox>  <mat-checkbox formControlName="checkbox3">Third Checkbox</mat-checkbox></form>

TypeScript

form: FormGroup;constructor(private formBuilder: FormBuilder){}ngOnInit(){  this.form = this.formBuilder.group({    checkbox1: [''],    checkbox2: [''],    checkbox3: [''],  });  this.form.setErrors({required: true});  this.form.valueChanges.subscribe((newValue) => {    if (newValue.checkbox1 === true || newValue.checkbox2 === true || newValue.checkbox3 === true) {      this.form.setErrors(null);    } else {      this.form.setErrors({required: true});    }  });}

Basically, subscribe to any changes in the form and then modify the errors as needed according to the new form values.