I have a custom validator that I'm using with my FormArray, the validator works fine as long as the input to the FormArray is []
. However if I provide the FormArray with a string[]
or FormControl[]
the validator will break the whole angular app and cause infinite looping errors.
I'm really not sure what is causing this to occur. I need to be able to instantiate the FormArray with elements so I need this to work.
At first I thought the problem was being caused by the fact I was passing a string[]
to the FormArray instead of FormControl[]
, but even after mapping the array to an array of FormControls I get the same problem.
this.alertData.alertContacts
is simply an array of email strings.
FormGroup instantiation - Works
this.form = this.formBuilder.group({
alertContacts: this.formBuilder.array([], [Validators.required, alertContactsArrayValidator()]),
});
FormGroup instantiation - Broken
this.form = this.formBuilder.group({
alertContacts: this.formBuilder.array(this.alertData.alertContacts, [Validators.required, alertContactsArrayValidator()]),
});
FormGroup instantiation - Broken
this.form = this.formBuilder.group({
alertContacts: this.formBuilder.array(this.alertData.alertContacts.map(x => new FormControl(x)), [Validators.required, alertContactsArrayValidator()]),
});
Custom Validator
export function alertContactsArrayValidator(): ValidatorFn {
return (c: AbstractControl): { [key: string]: any } | null => {
let formArray = <FormArray>c;
console.log(formArray);
let hasEmailErrors = false;
let formControls = formArray.controls;
console.log(formControls);
formControls.forEach(control => {
let controlErrors: ValidationErrors = control.errors;
console.log("Current control errors: ", controlErrors);
Object.keys(controlErrors).forEach(key => {
if (key === 'email') {
hasEmailErrors = true;
console.log("key has email");
}
});
});
return hasEmailErrors ? {'email': true} : null;
};
}
you need check if control.errors is null.
formControls.forEach(control => {
let controlErrors: ValidationErrors = control.errors;
if (controlErrors){ //<---this "if"
Object.keys(controlErrors).forEach(key => {
if (key === 'email') {
hasEmailErrors = true;
console.log("key has email");
}
});
}
});
You can also make simpler
formControls.forEach(control => {
if (control.errors && control.errors.email){
hasEmailErrors = true;
console.log("key has email");
}
});
even
formControls.forEach(control => {
hasEmailErrors = hasEmailErrors ||
(control.errors && control.errors.email)
}
});
NOTE: I think you want to make
this.form = this.formBuilder.group({
alertContacts: this.formBuilder.array(this.alertData.alertContacts
.map(x => new FormControl(x,[Validators.required,Validators.email])),
[alertContactsArrayValidator()]),
});
the FormsControls has required and email validator and the array the custom validator