1

I had condition in my reactive form where one checkbox selected, submit button will be enabled, and if there are none checkbox selected, it will remain disabled, the problem is I had selectAll function, which if I clicked, it will selected all the checkbox and enabled submit button, then if I unselect individual checkbox after select all function, the submit button should be enabled until all the checkbox is unselect, this is what I had tried:

ts file

  selectAll() {
    this.formReceivedSummons.controls.map(value => value.get('isChecked').setValue(true));
    return this.disabledButton = false;
  }

  changeCheck(event){
    this.disabledButton = !event.target.checked;
  }

html file

<div *ngIf="isShowResponse">
    <p>Inquiry Response</p>
    <form [formGroup]="form" (ngSubmit)="submitSelectedCheckboxes()">
        <ng-container formArrayName="receivedSummons" *ngFor="let 
            summon of formReceivedSummons.controls; let i = index">
            <ng-container [formGroupName]="i">
                <input type="checkbox" formControlName="isChecked"
        (change)="changeCheck($event)">
  {{ summon.get('isChecked').value ? 'selected' : 'select' }}
      </ng-container>
    </ng-container>
    <button [disabled]="disabledButton">Submit</button>
</form>
<button (click)="selectAll()">Select All</button>
</div>

supposed to be after select all function, submit button will enabled until all checkbox is unselected individually then it will disabled, this is my stackblitz demo, I could use any suggestion to solve this problem,

1
  • You have to maintain an array to store values for all checkboxes. So with select all, the value of all items in array is true. When any individual checkbox is unchecked, you make the value false in array for that checkbox. To disable Submit button, it will be disabled if all items in the array are false, else true. Commented Sep 28, 2019 at 8:04

3 Answers 3

1

the "clasic solution" is make a custom error validator

Imagine that you has some like

  options=["option 1","option 2","option 2"]
  form=new FormGroup({
      prop1:new FormControl(),
      receivedSummons:new FormArray(this.options.map(x=>new FormControl()),this.selectAtLeastOne())
  })

  selectAtLeastOne()
  {
    return (formArray:FormArray)=>{
      return formArray.value.some(x=>x)?null:{error:"At least one"}
    }
  }

You only need

  <button [disabled]="form.invalid">submit</button>

The completed form is like

  <div [formGroup]="form">
  <input formControlName="prop1">
  <div formArrayName="receivedSummons">
    <div *ngFor="let control of form.get('receivedSummons').controls;let i=index" >
      <input type="checkbox" [formControlName]="i">{{options[i]}}
    </div>
  </div>
  <button [disabled]="form.invalid">submit</button>
  </div>

NOTE: I choose use a formArray of FormControls, not a FormArray of formGroups, if you want to use a formArray of FormGroups, the code becomes like

  form2=new FormGroup({
      prop1:new FormControl(),
      receivedSummons:new FormArray(
         this.options.map(x=>new FormGroup({
           isChecked:new FormControl()
           })),this.selectAtLeastOne2())
  })

  selectAtLeastOne2()
  {
    return (formArray:FormArray)=>{
      return formArray.value.some(x=>x.isChecked)?null:{error:"At least one"}
    }
  }

And the .html

  <div [formGroup]="form2">
  <input formControlName="prop1">
  <div formArrayName="receivedSummons">
    <div *ngFor="let control of form.get('receivedSummons').controls;let i=index" [formGroupName]="i" >
      <input type="checkbox" formControlName="isChecked">{{options[i]}}
    </div>
  </div>
  <button [disabled]="form2.invalid">submit</button>
  </div>

You can see the two forms in stackblitz

Updated I add two funtions to check/uncheck all

  selectAll(select: boolean) {
    this.form.get("receivedSummons").setValue(this.options.map(x => select));
  }

  selectAll2(select: boolean) {
    this.form2.get("receivedSummons").setValue(
      this.options.map(x => {
        return { isChecked: select };
      })
    );
  }

The check to check/uncheck all like (see as I use a refernce variable to pass if is checkd or not the checkBox

  <input #check1 type="checkbox" (change)="selectAll(check1.checked)">Check All
Sign up to request clarification or add additional context in comments.

1 Comment

This is great, feel I gave him a immediate solution only. But your idea is totally welcome.
0

In html, define a reference in input "#checkboxes"

<input type="checkbox" formControlName="isChecked" #checkboxes (click)="changeCheck()">

In ts,

We can get all checkbox values using @ViewChildren

@ViewChildren("checkboxes") checkboxes: QueryList<ElementRef>; 

ViewChildren, QueryList, ElementRef to be imported from 'angular/core'

changeCheck(){
    let flag= true;
     this.checkboxes.forEach((element) => { // loop all checkboxes to find checked boxes
      if(element.nativeElement.checked){
        flag=false // if atleast one checkbox checked, put the flag flase
      }
    });

    this.disabledButton = flag;
  }

Working code at Stackblitz

2 Comments

Varman, your solution works, but I think that it's not an "angular solution". The clasic solution is make a custom validator
@jajanato if this answer is useful, please upvote and click tick to help others who seek this kind of question
0

Try the below code:

  changeCheck(event){
    let flag = true
    for (let summon of this.formReceivedSummons.controls){
      if(summon.get('isChecked').value) {
        flag = false
      }
    }
    this.disabledButton = flag
  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.