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 setting the error to the FormGroup. In other words, the FormGroup is always valid.
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(
map(patient => patient ? of(null) : of({valid: true})),
catchError(() => of(null))
);
};
}
}
The HTTP call is done perfectly when the two inputs loses the focus. But the error is not being set in the FormGroup.
I have tried these solutions:
#1. Adding bind() to the validator call
patientIdentifications: this.fb.group({
clinicRecord: [null, Validators.required],
documentId: [null, Validators.required]
}, {
updateOn: 'blur',
asyncValidators: CustomValidators.isPatientValid(this.myService).bind(this) // <= bind
}),
#2. Remove the of function
return myService.getPatient(clinicRecordValue, documentIdValue).pipe(
map(patient => patient ? null : {valid: true}), // <= remove the "of"
catchError(() => of(null))
);
#3. Setting the error directly using the FormGroup's instance
return myService.getPatient(clinicRecordValue, documentIdValue).pipe(
map(patient => patient ? formGroup.setErrors(null) : formGroup.setErrors({valid: true})),
catchError(() => of(null))
);
None of the solutions have worked for me.
My goal is to set the error to the FormGroup correctly to have the FormGroup as INVALID, which is the correct thing to do.
catchError(() => of(null))returnof({valid: true})since it's an error?mapforswitchMap.return formGroup.valueChanges.pipe(switchMap...or returning theswitchMapdirectly?return myService.getPatient(clinicRecordValue, documentIdValue).pipe( switchMap(patient => patient ? of(null) : of({valid: true})), catchError(() => of(null)) );of({valid: true})inside of thecatchError. Also, it works withswitchMapormap, although I don't understand the difference. I know whatswitchMapis for, but never seen it used like this. Lastly, I'm not sure if the correct thing to do isof(null)orformGroup.setErrors(null). If you could place the answer with the best approach I will accept it.