I have a reactive form and a form control that must unique:
this.form = new FormGroup({
name: new FormControl(this.initialValue, [
Validators.required,
], this._uniqueNameValidator.bind(this)),
});
I've wrote an async validator that calls a method from my app service:
private _uniqueNameValidator(control: FormControl) {
const value = control.value.trim();
if (value === '' || value === this.initialValue) {
return of(null);
}
control.markAsTouched();
return timer(500).pipe(
switchMap(() => {
return this._appService.validateName(value, this.selectedGroupId);
}),
map(response => {
return response ? {nameTaken: true} : null;
}),
catchError(() => {
return of(null);
})
);
}
The service method is a simple http GET that returns a boolean value:
validateName(name: string, groupId: number): Observable<boolean> {
// ...
return this._http.get<boolean>(url);
}
Working example: https://stackblitz.com/edit/angular-8kedup
Now, in my app a have many another forms with controls that must be unique. The uniqueness is checked async, but in other services methods and in other routes. I don't want to copy the code for the validator in every component that needs an async validator for uniqueness.
The problem: I want to write a generic validator, that takes as parameters a service method that must be called in order to determine if the value is unique or not, and the initial form value.
I wrote the following function:
export function UniqueAsyncValidator(fn: any, initialValue: string): AsyncValidatorFn {
return (control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
const value = control.value.trim();
if (value === '' || value === initialValue) {
return of(null);
}
control.markAsTouched();
return timer(500).pipe(
switchMap(() => {
return fn(value);
}),
map(response => {
return response ? {nameTaken: true} : null;
}),
catchError(() => {
return of(null);
})
);
};
}
And form definition:
this.form = new FormGroup({
name: new FormControl(this.initialValue, [
Validators.required,
], UniqueAsyncValidator(this._appService.validateName, this.initialValue).bind(this)),
});
It seems that the service method is called, but the context (this) in the service method is undefined:
validateName(name: string, groupId: number): Observable<boolean> {
// ....
console.log( 'this: ', this ); // -> returns undefined
return this._http.get<boolean>(url);
}
Example: https://stackblitz.com/edit/angular-sbbgc8
Thanks!