I am new to angular/ionic
I have parent checkbox, on click of it, I want to enable tick of all its child and vice versa
Here is my code i have tired but its not working:
home.html
<form [formGroup]="form">
<ion-item>
<ion-checkbox slot="start" formControlName="AllBulkhead" (ionChange)="checkBoxAllLongiClick($event)">
</ion-checkbox>
<ion-label>All longitudinal bulkheads</ion-label>
</ion-item>
<div class="subCheckbox">
<ion-item>
<ion-checkbox slot="start" formControlName="longiBulkhead" (ionChange)="checkBoxLongiClick($event)">
</ion-checkbox>
<ion-label>Longitudinal bulkheads</ion-label>
</ion-item>
<ion-item>
<ion-checkbox slot="start" formControlName="outerBulkhead" (ionChange)="checkBoxOuterLongiClick($event)">
</ion-checkbox>
<ion-label>Outer longitudinal bulkheads</ion-label>
</ion-item>
<ion-item>
<ion-checkbox slot="start" formControlName="innerBulkhead" (ionChange)="checkBoxInnerLongiClick($event)">
</ion-checkbox>
<ion-label>Inner longitudinal bulkheads</ion-label>
</ion-item>
</div>
</form>
home.ts
constructor(private _fb: FormBuilder){
this.form = this._fb.group({
AllBulkhead: false,
longiBulkhead: false,
outerBulkhead: false,
innerBulkhead: false,
});
}
checkBoxAllLongiClick(e) {
if (e.currentTarget.checked) {
this.form.controls['longiBulkhead'].patchValue(true);
this.form.controls['outerBulkhead'].patchValue(true);
this.form.controls['innerBulkhead'].patchValue(true);
}
else {
this.form.controls['longiBulkhead'].patchValue(false);
this.form.controls['outerBulkhead'].patchValue(false);
this.form.controls['innerBulkhead'].patchValue(false);
}
}
checkBoxLongiClick(e){
this.checkBoxSubLongiClick();
}
checkBoxOuterLongiClick(e){
this.checkBoxSubLongiClick();
}
checkBoxInnerLongiClick(e){
this.checkBoxSubLongiClick();
}
checkBoxSubLongiClick() {
if (this.form.get('longiBulkhead').value &&
this.form.get('outerBulkhead').value &&
this.form.get('innerBulkhead').value) {
this.form.controls['AllBulkhead'].patchValue(true);
} else {
this.form.controls['AllBulkhead'].patchValue(false);
}
}
What i want to do is when i click on AllBulkhead checkbox, I want to check/uncheck all 3 of its child check-boxes i.e longiBulkhead,outerBulkhead,innerBulkhead
below is my code is giving unexpected behavior when i untick any of 3 child checkboxes so it is not un-cheking the parent checkbox i.e AllBulkhead checkbox
Where i am making mistake can any one help me ? Thank you in advance!
I think the problem is that changing the "all" option also triggers a change in the other options, which at the same time tries to change the "all" option again. It's not very easy to notice this, but if you add a few console.log('...');
you'll find that the method that updates the state of the options is called a few more times than what you'd expect.
A better way to handle this would be to leave the "all" option outside of the form. The reason behind this is that the "all" option is not really an option, but a side effect based on the state of the other options. And by leaving it outside of the form, we can control when and how it should be updated without having any issues related to the change on an option triggering the change on another option behind the scenes.
Please also notice that as of Ionic 4.1.0 the ion-checkbox
component has an indeterminate
state that may be useful for scenarios like this one. It's a common UI/UX practice that if you select only some of several options (but not all of them) instead of showing the "all" option as unchecked, it's shown in an indeterminate state.
Anyway, please take a look at this working Stackblitz demo:
Like you can see in the demo, I'm keeping the state of the "all" option outside of the form:
public form: FormGroup;
public allOptionStateChecked = false;
public allOptionStateIndeterminate = false;
constructor(private formBuilder: FormBuilder) {}
ngOnInit() {
this.form = this.formBuilder.group({
option1: false,
option2: false,
option3: false
});
}
And I'm setting its state manually using those properties (by also using the click
handler instead of ionChange
):
<ion-item (click)="onAllChange()" lines="none">
<ion-checkbox
slot="start"
[checked]="allOptionStateChecked"
[indeterminate]="allOptionStateIndeterminate">
</ion-checkbox>
<ion-label>All</ion-label>
</ion-item>
I also have some helper methods that tell me if all or some of the options are checked:
private allChecked(): boolean {
const option1Value = this.form.get("option1").value;
const option2Value = this.form.get("option2").value;
const option3Value = this.form.get("option3").value;
return option1Value && option2Value && option3Value;
}
private someChecked(): boolean {
const option1Value = this.form.get("option1").value;
const option2Value = this.form.get("option2").value;
const option3Value = this.form.get("option3").value;
return !this.allChecked() && (option1Value || option2Value || option3Value);
}
And with all that in place, there are only two things to be done:
public onAllChange(): void {
const nextValue = this.allChecked() ? false : true;
this.form.get("option1").patchValue(nextValue);
this.form.get("option2").patchValue(nextValue);
this.form.get("option3").patchValue(nextValue);
}
public onOptionChange(): void {
this.allOptionStateChecked = this.allChecked();
this.allOptionStateIndeterminate = this.someChecked();
}
Please notice that I don't update allOptionStateChecked
and allOptionStateIndeterminate
in the onAllChange()
method. Since the state of the "all" option is a side effect based on the state of the other options, its state is updated in the onOptionChange()
instead.
Based on your comment I've updated the Stackblitz demo to also include the "all" option as part of the form but still, the difference with your code is that I manually set the state of the "all" option instead of binding it to the view using something like formControlName="all"
:
...
ngOnInit() {
this.form = this.formBuilder.group({
all: false, // <-- added this to the form
option1: false,
option2: false,
option3: false
});
}
...
public onOptionChange(): void {
this.allOptionStateChecked = this.allChecked();
this.allOptionStateIndeterminate = this.someChecked();
// Added this line at the end of the method!
this.form.get("all").patchValue(this.allOptionStateChecked);
}