Reputation: 41
I have a list of angular checkboxes and need to validate if at least one is selected.
The checkbox items are dynamic(they come from a service) so it is not a static list. One time it could have 3 elements and other time could have 50+ etc.
The template goes like this:
<tr *ngFor="let recipient of recipients">
<td class="disable edit">
<div>
<span class = "textbluesmall"><input type="checkbox" [checked]="true" value="{{recipient?.participantId }}" name="participant" />{{recipient?.lastName }} ,{{recipient?.firstName }}</span>
</div>
</td>
<td class="disable edit">
<div>
<span>{{recipient?.email }}</span>
</div>
</td>
</tr>
And I'm trying to solve this way but it is not working
.TS FILE:
var checkboxs=document.getElementsByName('participant');
var okay=false;
for(var i=0,l=checkboxs.length;i<l;i++)
{
if(checkboxs[i].checked){
okay=true;
break;
}
}
if(okay){
return true;
}
else{
return false;
}
}
How can I do this the easiest way?
Upvotes: 3
Views: 7770
Reputation: 143
Less work: set required attribute dynamically true when nothing is selected, this will invalidate your form.
// ANGULAR
check(recipients): boolean {
return !recipients.some(el => el.checked);
}
// HTML
<ng-form #recipientForm="ngForm" name="form">
<input type="checkbox"
[required]="check(recipients)" />
Upvotes: 0
Reputation: 959
your constructor
constructor(private formBuilder: FormBuilder) {
this.form = this.formBuilder.group({
recipients: new FormArray([], minSelectedCheckboxes(1))
});
add this function
function minSelectedCheckboxes(min = 1) {
const validator: ValidatorFn = (formArray: AbstractControl) => {
if (formArray instanceof FormArray) {
const totalSelected = formArray.controls
.map((control) => control.value)
.reduce((prev, next) => (next ? prev + next : prev), 0);
return totalSelected >= min ? null : { required: true };
}
throw new Error('formArray is not an instance of FormArray');
};
return validator;
}
Upvotes: 6
Reputation: 41
The correct way to do this is with Reactive Forms as @thisdotutkarsh answered. But actually if you need to do it the "Raw way" you can do it like this:
validateCheckboxes() {
this.vals = document.getElementsByName('participant');
var recpNum = 0;
for (var i = 0, n = this.vals.length; i < n; i++) {
if (this.vals[i].checked ){
recpNum++;
}
}
if(recpNum == 0){
return false;
}else{
if(recpNum > 0){
return true
}
}}
Upvotes: 0
Reputation: 980
As the checkboxes have to be created dynamically, you need to use Reactive Forms
in Angular.
Reactive Forms
are primarily composed of three types of classes, namely,
FormGroups
FormArray
FormControl
To be able to create checkboxes, dynamically you would need to start by importing FormsModule
and ReactiveFormsModule
inside your module.ts file, and add them to the imports
array of your @NgModule
decorator.
Similarly import FormBuilder
and FormGroup
in your component.ts file. Then use the FormBuilder
service to create your FormGroup
that will be declared in your template.
export class AppComponent {
form: FormGroup;
arrayOfRecepients = [];
constructor(private formBuilder: FormBuilder) {
this.form = this.formBuilder.group({
recipients: new FormArray([])
});
}
}
In your template file, bind the form element with [formGroup]="form"
<form [formGroup]="form">
<!-- Template code for checkboxes -->
</form>
Iterate through your array of recipients to push new instances of FormControl
to FormArray
. Set the control to false, so that the checkboxes are marked unchecked. This way the form array will consider each individual checkbox as a part of its collection of controls.
this.arrayOfRecepients.forEach(() => this.recipientsFormArray.push(new FormControl(false)));
In your template file, iterate over your array of recipients using the *ngFor
directive. Define the formArrayName
as recipients as it is required for informing the form API.
<form [formGroup]="form" (ngSubmit)="submit()">
<label formArrayName="recipients" *ngFor="let recepient of recipientFormArray.controls; let i = index">
<input type="checkbox" [formControlName]="i">
{{arrayOfRecipients[i].name}}
</label>
</form>
For validating the checkboxes, you would need to pass in your validator function as a second parameter to the FormArray
.
The validator function should be such that it takes your formArray
and count of least checked checkboxes required, as input. It should grab the values of the control, calculate the count of control values that are true, and then compare the count with the minimum.
TLDR;
For your reference please find link to a working demo here
Upvotes: 1