When this.from.valid returns false, I utilize the following approach to identify the first invalid control and handle the error in my component. While this method works well for form groups without any form array, is there a way to identify the first invalid control of a Form Array?
get-form-validation-errors.ts
import {
AbstractControl,
FormArray,
FormGroup,
ValidationErrors
} from '@angular/forms';
export interface AllValidationErrors {
control_name: string;
error_name: string;
error_value: any;
control_modified: string;
}
export interface FormGroupControls {
[key: string]: AbstractControl;
}
// Function to get validation errors from form controls
export function getFormValidationErrors(
controls: FormGroupControls
): AllValidationErrors[] {
let errors: AllValidationErrors[] = [];
Object.keys(controls).forEach((key) => {
const control = controls[key];
if (control instanceof FormGroup) {
errors = errors.concat(getFormValidationErrors(control.controls));
control.markAsTouched({
onlySelf: true
});
} else if (control instanceof FormArray) {
for (const arrayControl of control.controls) {
if (arrayControl instanceof FormGroup) {
errors = errors.concat(
getFormValidationErrors(arrayControl.controls)
);
}
}
}
const controlErrors: ValidationErrors = controls[key].errors;
if (controlErrors !== null) {
Object.keys(controlErrors).forEach((keyError) => {
errors.push({
control_name: key,
error_name: keyError,
control_modified: beautifyControl(key),
error_value: controlErrors[keyError]
});
});
}
});
return errors;
}
// Function to beautify control names
function beautifyControl(key: string): string {
let result: string[] = [];
const splitters = ['-', '_'] as const;
if (key.includes(splitters[0])) result = key.split(splitters[0]);
else if (key.includes(splitters[1])) result = key.split(splitters[1]);
else result = key.replace(/([a-z])([A-Z])/g, '$1 $2').split(' ');
return [
...result.map((e: string, i: number) => e[0].toUpperCase() + e.slice(1))
].join(' ');
}
Using example:
// Checking form validity and handling errors
if (!this.formValid()) {
const error: AllValidationErrors = getFormValidationErrors(this.regForm.controls).shift();
if (error) {
let text;
switch (error.error_name) {
case 'required': text = `${error.control_name} is required!`; break;
case 'pattern': text = `${error.control_name} has wrong pattern!`; break;
case 'email': text = `${error.control_name} has wrong email format!`; break;
case 'minlength': text = `${error.control_name} has wrong length! Required length: ${error.error_value.requiredLength}`; break;
case 'areEqual': text = `${error.control_name} must be equal!`; break;
default: text = `${error.control_name}: ${error.error_name}: ${error.error_value}`;
}
this.error = text;
}
return;
}