this.from.valid returns false I am using this approach below to get the first invalid control and throwing the error accordingly in my component. This approach is working fine form groups without any form array.
Is there a way to find out 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;
}
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 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:
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;
}