I would like to implement an async
cross-field validator which will fetch some results from my backend.
Here is the relevant part of the component:
export class MemberComponent implements OnInit {
private _form: FormGroup = new FormGroup({
activity: new FormControl(null),
account: new FormControl(null),
role: new FormControl(null),
fare: new FormControl(null),
info: new FormControl(null),
}, {
validators: new ValidateMemberNotTaken(this._memberService)
});
constructor(private _memberService: MemberService){}
...
Here is my implementation of the validator:
export class ValidateMemberNotTaken implements AsyncValidator {
constructor(private memberService: MemberService) {}
validate(control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {
const {activity, account, role} = control.value;
return this.memberService.exists(activity,account,role).pipe(
map(exists => (exists ? { memberExists: true } : null)),
catchError(() => of(null))
);
}
}
and here is the function exists
used in my validator:
@Injectable({
providedIn: 'root'
})
export class MemberService {
private _apiUrl = 'http://localhost:3000/api/members';
constructor(
private _http: HttpClient,
) {
}
exists(activityId: number, accountId: number, roleId: number): Observable<boolean> {
const url = `${this._apiUrl}/activity/${activityId}/account/${accountId}/role/${roleId}`;
return this._http.get<boolean>(url);
}
}
When compiling my code, I get the following error:
Error: src/app/components/member/member.component.ts:31:6 - error TS2345: Argument of type '{ validators: ValidateMemberNotTaken; }' is not assignable to parameter of type 'ValidatorFn | ValidatorFn[] | AbstractControlOptions'.
Is it possible to implement cross-field async validators ? If so could you please tell me what is wrong with my code ?
CodePudding user response:
I don't know why you are making a class of the Validator, we usually use functions for custom validators (async and sync) and that is what I would suggest:
export function validateMemberNotTaken(memberService): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
if (control) {
const {activity, account, role} = control.value;
return memberService.exists(activity,account,role).pipe(
map(exists => (exists ? { memberExists: true } : null)),
catchError(() => of(null))
);
}
return of(null);
};
}
Import the function and then mark the validator as follows in your formgroup:
validators: validateMemberNotTaken(this._memberService)