Reputation: 11
I have a form which contains a set of checkboxes and I want to create a custom validator that forces to check at least one of them.
In form.component.ts
:
form: FormGroup = new FormGroup({
customer: new FormControl('', [Validators.required]),
partTimeidentification: new FormControl('', [Validators.required]),
inspectionType: new FormGroup({
ocr: new FormControl(false, []),
anomalyDetection: new FormControl(false, []),
metrics: new FormControl(false, []),
wiresInspection: new FormControl(false, []),
other: new FormControl(false, []),
}, { validators: atLeastOneValidator() }),
cameraSettings: new FormGroup({
model: new FormControl('', [Validators.required]),
size: new FormControl('', [Validators.required]),
speedOb: new FormControl('', [Validators.required]),
flashColor: new FormControl('', [Validators.required]),
}),
});
In form.component.html
(I omitted fields to keep it as clear as possible, you have the structure up here):
<form class="flex-col text-center" [formGroup]="form!">
(more fields here)
<app-box [title]="'Inspection type'" class="text-center me-2" [fit_height]="true" formGroupName="inspectionType">
<div class="form-check">
<input class="form-check-input" type="checkbox" formControlName="ocr" name="ocr" value="ocr"/>
<label class="form-check-label"> OCR </label>
</div>
(more checkboxes)
</app-box>
(more fields)
<button [disabled]="!form!.valid" type="button" class="btn bg-primary-tb text-white mt-3 col-4" (click)="submit()">Continue </button>
</form>
atLeastOneValidator.directive.ts
:
import { AbstractControl, ValidationErrors, ValidatorFn } from "@angular/forms";
export function atLeastOneValidator(): ValidatorFn {
return (group: AbstractControl): ValidationErrors | null => {
let controls = group.parent.controls;
let theOne = Object.keys(controls).findIndex(key => controls[key].value !== false);
if (theOne) return null;
return { 'atLeastOneRequired': 'At least one should be selected'}
};
};
Nevertheless, I keep receiving the error message error TS2531: Object is possibly 'null'.
in the validator's group.parent
.
To put the validator's code into words: I want to access the parent (what I guess it is inspectionType
, a FormGroup
) and then look if any of the children (ocr
, anomalyDetection
... any of those FormControl
s) are set to true, in that case the form is valid.
Upvotes: 0
Views: 1709
Reputation: 2797
Create a validator which expects a FormGroup
and then append the validator to the FormGroup
which is the parent to the FormControl
of which at least one must be true.
// validator
function atLeastOneValidator() {
return (control: FormGroup) => {
const raw = control.getRawValue();
return Object.keys(raw).map(k => raw[k]).some(_ => _) ? null : {check_one: "Must check at least one"}
}
}
// form group
fg: FormGroup;
constructor(private fb: FormBuilder) {
this.fg = this.fb.group({
a: this.fb.control(false),
b: this.fb.control(false),
c: this.fb.control(false),
}, {validators: [atLeastOneValidator()]});
}
minimal stackblitz: https://stackblitz.com/edit/angular-ivy-f3c3e1?file=src/app/app.component.ts
Upvotes: 1