I have Angular formArray of checkboxes. I also have a validator that makes sure at least one of the checkboxes is selected.
My problems are:
When the last checkbox is selected, I want to deselect all the other checkboxes.
When the user again select any of the checkboxes (except the last one), the last checkbox (which is already selected) must be deselected.
IMPORTANT: The user can select either the last checkbox or any number of other checkboxes. For instance if he selects the last checkbox and then click on any of the other checkboxes, then the last checkbox must be deselected.
The validator works perfect but when the last checkbox is selected, the other selected checkboxes are not deselected.
Though I think I have done the right thing but my browser console tells me that there are too many recursions and because of that it is not working.
The following link is my Stackblitz code where you can test the feature and see the source code.
(Click the Project icon in Stackblitz to open the file browser to see all the files).
The main issue here (after realising you need {emitEvent: false}
when you setValue
is that you need not just the checkbox values but the previous one to know which one changed.
This can be acheived with the RxJs pipeable operator scan
get bookArray() {
return this.booksForm.controls['books'] as FormArray
}
this.bookArray.valueChanges.pipe(
tap((val) => console.log(val)), // e.g. [false, false, true, false, false]
distinctUntilChanged(),
scan((acc, curr) => !acc && curr[curr.length - 1], false), // True only if None of the above has been selected
tap((val) => console.log(val)), // e.g. true or false
).subscribe((lastBookSelected: Boolean)=> {
if (lastBookSelected) {
this.bookArray.controls.forEach(control => {
this.deselectBooks(control)
console.log('here')
})
} else {
// set last control false but use `{emitEvent: false}`
}
})
Note {emitEvent: false}
is required on deselectBooks
:
private deselectBooks(control: AbstractControl) {
this.bookArray.controls.map((book, index) => index !== (this.bookArray.length - 1) ? book.setValue(false, {emitEvent: false}) : null);
}
Stackblitz - https://stackblitz.com/edit/angular-tx5cpe