0
votes

I'm doing a web application in Angular 10 with a simple form to receive two values that I will be validating them on the backend, doing a HTTP call. To accomplish this I have created an async validator which runs perfectly.

Problem: It's not clearing the error completely in the FormGroup when the HTTP call is a success. In other words, the FormGroup is always INVALID.

enter image description here

Inside of errors object of the FormGroup, there is two strange things that I don't know about, isScalar and subscribe. Maybe this is the issue?

Behaviors that I'm presenting:

  1. HTTP call was failed: the error is being set correctly and the status is INVALID. All good.
  2. HTTP call was success: the error is not being cleared completely and the status is INVALID. Bad!!

FormGroup

this.form = this.fb.group({
  // I will validate this two values with the backend
  patientIdentifications: this.fb.group({
    clinicRecord: [null, Validators.required],
    documentId: [null, Validators.required]
  }, {
    updateOn: 'blur',
    asyncValidators: CustomValidators.isPatientValid(this.myService) // <= async validator
  }),
  // Just to illustrate that I have more FormControls
  firstName: [null, Validators.required],
});

Async validator

export class CustomValidators {

  static isPatientValid(myService: MyService): AsyncValidatorFn {
    return (formGroup: FormGroup):
      Promise<ValidationErrors | null> |
      Observable<ValidationErrors | null> => {

      const clinicRecordControl = formGroup.controls.clinicRecord;
      const documentIdControl = formGroup.controls.documentId;
      const clinicRecordValue = clinicRecordControl.value;
      const documentIdValue = documentIdControl.value;

        return myService.getPatient(clinicRecordValue, documentIdValue).pipe(
          // Returning "null" if there is a response to clear the FormGroup's errors.
          map(patient => patient ? of(null) : of({valid: true})),
          catchError(() => of({valid: true}))
        );
    };
  }

}

The HTTP call is done perfectly when the two inputs loses the focus. But the FormGroup remains as INVALID even if the HTTP call was a success.

My goal is to clear the error of the FormGroup correctly when the HTTP call was a success to have the FormGroup as VALID.

1

1 Answers

1
votes

Example my email realtime exist checker. Crutches for you.

// In component
this.form = new FormGroup({
    // ...
    email: new FormController(
        'email',
        [...],
        [ValidatorsHelper.isEmailExistValidator(this.http)]
    ),
    // ...
};



// Async validator
class ValidatorsHelper {
    // ...

    static isEmailExistValidator(http: HttpClient): AsyncValidatorFn {
        return (control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
            return http.post<boolean>(AUTH_REG_EMAIL, { data: control.value }).pipe(
                map((result) => result ? null : { exist: true }),
                catchError(() => {
                    return of({ exist: true });
                }),
            );
        };
    }

    // ...
}

Essentially: return (formGroup: FormGroup): -> return (control: AbstractControl):

In form.d.ts:

export declare interface AsyncValidatorFn {
    (control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null>;
}

Update: A questioning colleague missed that he used of(null) in map. of(null) requires swtichMap, while plain null requires map. Details can be found in a comment below the answer.