Search code examples
angulartypescriptrxjsangular-validation

Debounce async Validator


I have a working async validator that does an HTTP request to the server to check if a username is already taken. As I don't want to call the API after each keystroke I need to debounce the input stream.

I first had throttleTime in the service, but another topic on SO said this has to be on the one who subscribes, but no luck yet!

My Component:

this.form = this._fb.group(
      {
        username: ['', [Validators.required, Validators.maxLength(50), NoWhitespaceValidator], [IsUserIdFreeValidator.createValidator(this._managementService)]]
      });

My Validator:

export class IsUserIdFreeValidator {
  static createValidator(_managementService: ManagementService) {
    return (control: AbstractControl) => {
      return _managementService.isUserIdFree(control.value)
        .pipe(
          throttleTime(5000),
          (map(
            (result: boolean) => result === false ? { isUserIdFree: true } : null))
        );
    };
  }
}

My Service:

  public isUserIdFree(userId: string): Observable<{} | boolean | HttpError> {
    const updateUserCheck: UpdateUserCheck = new UpdateUserCheck();
    updateUserCheck.userID = userId;

    return this._httpClient.post<boolean>('UserManagementUser/IsUserIdFree', updateUserCheck));
  }

Solution

  • I was able to solve this trough another way, via a propery called 'updateOn' on the control.

    With template-driven forms:

    <input [(ngModel)]="name" [ngModelOptions]="{updateOn: 'blur'}">
    

    With reactive forms:

    new FormControl('', {updateOn: 'blur'});
    

    If you use the form-builder, since Angular 7 you can use this:

    this.form = this._fb.group({
      email: ['', [CustomValidators.email], null, 'blur'],
    });