0

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 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

6 Comments

Why don't you return of(null) if the function needs to return a Promise or an Observable? This is the only difference that I can see between me and your solution. Could you explain more please?
Because, I use map, not switchMap.
Essentially: use map if just value will be modified and switchMap when return observable or promise. You just set value to of(null) what return observable. So you have to swichMap. Another option return null without of() in map
Happiness? :D Every thing is ok?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.