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

后端 未结 6 1830
遇见更好的自我
遇见更好的自我 2020-12-04 22:20

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



        
相关标签:
6条回答
  • 2020-12-04 22:34

    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.

    0 讨论(0)
  • 2020-12-04 22:37

    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.

    0 讨论(0)
  • 2020-12-04 22:43

    You should be checking the touched and dirty conditions of the form element

    <form #myForm="ngForm"  *ngIf="active"  (ngSubmit)="onSubmit()">
    
        <div class="form-group">
            <label for="name">Name</label>
            <input type="text" id="name" class="form-control"
                   required name="name" [(ngModel)]="myform.name"
                   #name="ngModel" >
            <div *ngIf="name.errors && (name.dirty || name.touched)"
                 class="alert alert-danger">
                <div [hidden]="!name.errors.required">
                  Name is required
                </div>
            </div>
        </div>
    
    </form>
    

    You can combine the previous and my answer for both scenarios

    0 讨论(0)
  • 2020-12-04 22:48

    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.

    0 讨论(0)
  • 2020-12-04 22:54

    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");
    }
    
    0 讨论(0)
  • 2020-12-04 22:57

    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

    0 讨论(0)
提交回复
热议问题