0
votes

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;
  };
}
1

1 Answers

1
votes

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