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? – Chrillewoodzmap
forswitchMap
. – Chrillewoodzreturn formGroup.valueChanges.pipe(switchMap...
or returning theswitchMap
directly? – RRGT19return myService.getPatient(clinicRecordValue, documentIdValue).pipe( switchMap(patient => patient ? of(null) : of({valid: true})), catchError(() => of(null)) );
– Chrillewoodzof({valid: true})
inside of thecatchError
. Also, it works withswitchMap
ormap
, although I don't understand the difference. I know whatswitchMap
is 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. – RRGT19