0
votes

I need to check that username typed by user is unique. Thus, I'm sending an HTTP request for every input event from the target element. And, of course, I need to debounce this operation, so as to get 1 HTTP request for X input events following each other within a specific interval.
The problem is - as soon as I add switchMap the code stops working and switchMap callback is never called.
The working code without a switchMap:

public static createUniqueFieldValidator(
  target: 'username' | 'email' | 'phone',
  checker: (value: string) => boolean,
  userService: UserService
): AsyncValidatorFn {
  return (control: AbstractControl): Observable<NullableType<ValidationErrors>> => {
    if (!!control.value && checker(control.value)) {
      return fromPromise<SomeReturnedType>(
        userService.checkUnique({ [ target ]: control.value })
      ).pipe<NullableType<ValidationErrors>>(.......);
    }

    return of<null>(null);
  };
}

If I add a switchMap its callback is never called

public static createUniqueFieldValidator(
  target: 'username' | 'email' | 'phone',
  checker: (value: string) => boolean,
  userService: UserService
): AsyncValidatorFn {
  return (control: AbstractControl): Observable<NullableType<ValidationErrors>> => {
    if (!!control.value && checker(control.value)) {
      // We do get here, I've checked
      return timer(300).pipe<NullableType<ValidationErrors>>(
        switchMap<number, Observable<NullableType<ValidationErrors>>>(
          (): Observable<NullableType<ValidationErrors>> => {
            console.log('SwitchMap');// The whole callback is never called
            // Here I'm supposed to make an HTTP request instead of returning a null
            return of<null>(null);
          }
        )
      );
    }

    return of<null>(null);
  };
}

If I replace timer with

of<string>(control.value).pipe<NullableType<ValidationErrors>>(delay(), switchMap.......)

it doesn't work either.
If I replace switchMap with switchMapOf it works but without a debounce time.

1
Do you want timer or debounceTime? NOTE: Rememeber that if your inputs has another sync Validator and not pass, the asyncValidator is not executedEliseo
What I need is if, for example, user types "qwerty", app should send 1 request to the API instead of 1 request for each char. Sync validators are passed, but I tried to remove them completely, nothing changed. About timer / debounceTime - look at the end of the topic, the of / delay option seems more reasonable to me but doesn't work either. It looks like Observable is stopped being subscribed to once you add a switchMap.WeekendMan

1 Answers

0
votes

Take a look to this SO

Well, you can create your validator like:

checkIfNotRegister(): AsyncValidatorFn {
    return (control: AbstractControl): Promise<ValidationErrors | null> |
                                       Observable<ValidationErrors | null> => {
      return timer(1000).pipe(switchMap(_=>this.service.getWebName(control.value).pipe(
        map(res => res ? { repeat: "name yet register" } : null)
      )))

    };
  }

But you see in this forked stackblitz that the message "Validating.." is showed each change of the input -if you change the timer by 10000ms, this effect is more observable-