Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I want to do validation for checkboxes here without form tag. At least one checkbox should be selected.

<div *ngFor="let item of officeLIST">
  <div *ngIf=" item.officeID == 1">
    <input #off type="checkbox" id="off" name="off" value="1" [(ngModel)]="item.checked">
    <label>{{item.officename}}</label>
  </div>

  <div *ngIf="item.officeID== 2">
    <input #off type="checkbox" id="off" name="off" value="2" [(ngModel)]="item.checked">
    <label>{{item.officename}}</label>
  </div>

  <div *ngIf="item.officeID== 3">
    <input #off type="checkbox" id="off" name="off" value="3" [(ngModel)]="item.checked">
    <label>{{item.officename}}</label>
  </div>
</div>

for other field I will put required and do the error|touched|valid etc. but since checkbox is not single input, I cannot put required in every checkbox because all checkbox will be compulsory to checked. so how do I do the validation to alert user atleast one should be checked?

like image 992
user3431310 Avatar asked Apr 13 '17 06:04

user3431310


People also ask

How do you check if atleast one checkbox is selected?

$('#frmTest'). submit(function(){ if(! $('#frmTest input[type="checkbox"]').is(':checked')){ alert("Please check at least one."); return false; } }); is(':checked') will return true if at least one or more of the checkboxes are checked.

How can I require at least one checkbox be checked before a form can be submitted?

How can I enforce that requirement? You could use PHP to check if at least 1 of the check boxes is checked. You would probably also want to make sure your <input "name"> is different for each check box otherwise getting the return variable values might be tricky.

How do you validate a form with multiple checkboxes to have atleast one checked?

jQuery. validator. addMethod("validatorName", function(value, element) { if (($('input:checkbox[name=chkBox1]:checked'). val() == "Val1") || ($('input:checkbox[name=chkBox2]:checked').

How do you evaluate a checkbox selection?

Checking if a checkbox is checked First, select the checkbox using a DOM method such as getElementById() or querySelector() . Then, access the checked property of the checkbox element. If its checked property is true , then the checkbox is checked; otherwise, it is not.

How do you check if a checkbox is checked?

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.

How to validate an array of items in a checkbox?

On validation (i.e for example some click event) iterate over your array and check whether at least one item is true. Add (ngModelChange)="onChange (officeLIST)" to your checkbox and have below code in your .ts file.

Can I have multiple checkboxes with the same name?

You should avoid having two checkboxes with the same name if you plan to reference them like document.FC.c1. If you have multiple checkboxes named c1 how will the browser know which you are referring to? Here's a non-jQuery solution to check if any checkboxes on the page are checked.

Which button should I use to check box or radio button?

If you have a different answer for this question, then please use the Your Answer form at the bottom of the page instead. If your requirement is to have only one option selected at a given point of time, then u should go for RADIO BUTTON else if multiple options to be selected, then CHECK BOX.


5 Answers

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

like image 58
Mick Avatar answered Oct 23 '22 09:10

Mick


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 formcontrol
checkboxGroup.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.

like image 22
Pengyy Avatar answered Oct 23 '22 10:10

Pengyy


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

HTML Note: 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.

like image 34
eper Avatar answered Oct 23 '22 10:10

eper


On validation (i.e for example some click event) iterate over your array and check whether at least one item is true.

let isSelected: any = this.officeLIST.filter((item) => item.checked === true);
if(isSelected != null && isSelected.length > 0) {
 //At least one is selected
}else {
 alert("select at least one");
}
like image 36
Nugu Avatar answered Oct 23 '22 11:10

Nugu


Add (ngModelChange)="onChange(officeLIST)" to your checkbox and have below code in your .ts file.

onChange(items) {
    var found = items.find(function (x) { return x.checked === true; });
    if (found)
      this.isChecked = true;
    else
      this.isChecked = false;
  }

Use isChecked variable any places you want.

like image 1
shailesh kumar Avatar answered Oct 23 '22 09:10

shailesh kumar