I want to validate form that at least one field is not empty - at least one field is filed. I created custom validator:
import { FormControl, FormGroup, ValidationErrors, ValidatorFn } from "@angular/forms";
export const pfkValidator: ValidatorFn = (abstractControl: AbstractControl): ValidationErrors | null => {
let fg = (abstractControl as FormGroup);
let isValid = false;
Object.keys(fg.controls).forEach(
field => {
const ctrl = fg.get(field);
if (ctrl instanceof FormControl) {
console.log('ctrl value', ctrl.value);
if (ctrl.value) {
isValid = true;
}
}
});
if (isValid) return { 'valid': true }
return null;
}
This is how form is initialized:
ngOnInit(): void {
this.form = this.fb.group({
Field1: [null],
Field2: [null],
Field3: [null],
Field4: [null],
Field5: [null],
Field6: [null],
Field7: [null],
Field8: [null],
Field9: [false],
Field10: [false],
}, { validators: pfkValidator });
}
Issue is when forms loads, validation is activated for every field, which takes quite a time. My form has 10 fields and I have logged 10x10 inputs in console.
Is this expected behavior?
Below is your implementation which shows 121 logs in the console
However in below implementation using FormArrays
I have tried to reduce the running operations to avoid the loops Demo using FormArrays. The console now shows only 14 logs initially with 1 log per edit. You may even add updateOn: 'blur'
to improve perfomance even further
export const pfkValidator: ValidatorFn = (
abstractControl: AbstractControl
): ValidationErrors | null => {
console.log("ctrl value", abstractControl.value.join(""));
if (abstractControl.value.join("") !== "") {
return { atLeastOne: false };
}
return null;
};
This can be implemented like below
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {}
get fields() {
return this.form.get("fields") as FormArray;
}
ngOnInit(): void {
this.form = this.fb.group({
fields: this.fb.array(
[null, null, null, null, null, null, null, null, false, false],
{ validators: [pfkValidator] }
)
});
}
}
and in the html
<form [formGroup]='form'>
<ng-container formArrayName='fields'>
<input *ngFor="let control of fields.controls; let i = index" [formControlName]="i">
</ng-container>
</form>