0

switchMap does not repeat HTTP calls.

I have created a directive that validates an email if it already exists.

Inside that directive, is an API. Every time a keypress happens, the API is being called to check if it already exists.

I'm using switchMap to prevent multiple HTTP requests and cancel previous ones.

But the problem is once the request has already been made and canceled, it would not repeat again.

e.g. test@gmail.com - canceled request

test2@gmail.com - successful API

test@gmail.com (again) - the API call will not happen anymore.

Why is this happening (to me) ??

I have checked switchMap operator docs and I do not see any situations regarding about this.

<input [(ngModel)]="sampleEmail" placeholder="Email"  isEmailExistsValidator>

export class isEmailExistsValidator implements AsyncValidator {
  constructor(private someService: SomeService) { }
  public validate(control: AbstractControl): Observable<ValidationErrors|null> { 

if (isNullOrUndefined(control.value)) {
  return of(null);
} 

return this.someService
  .isEmailExistsValidator(control.value)
  .pipe(
    switchMap((response) => {
      if (response.availability) {
        return of(null);
      } else {
        return of({ emailAlreadyExists: response.response });
      }
    })
  );
  }

}

public isEmailExistsValidator(email: string): Observable<EmailAvailability> {
return this.httpClient.get<EmailAvailable>('/api/sampleEmailValidation/' + email);

}

I expect the API to be successful in any email input.

  • 1
    Please share the code for `someService.isEmailExistsValidator`. – Alexander Staroselsky Sep 04 '19 at 15:53
  • I'm not sure this is the right usage of `switchMap`. Inside `switchMap` you should perform requests. I think the problem is that `this.someService.isEmailExistsValidator` **completes** after it was successful. Sharing the code for `this.someService.isEmailExistsValidator` would be helpful. – Andrei Gătej Sep 04 '19 at 18:02
  • @AlexanderStaroselsky its an GET request that returns if the email exists –  Sep 04 '19 at 18:16
  • @AndreiGătej the isEmailExistsValidator is a GET requests that returns if the email exists –  Sep 04 '19 at 18:18
  • 1
    Yes, but if you are using the `HttpClient`, after each request, the observable completes. You can check that, even in your exemple, if you place the cb for 'completed'. – Andrei Gătej Sep 04 '19 at 18:19
  • What status does the API return if an email is already used? Does it return 200 and that object structure or does it return some kind of 4xx or 5xx error? – Alexander Staroselsky Sep 04 '19 at 22:59
  • @AlexanderStaroselsky it returns 200 and a message that it is already taken –  Sep 05 '19 at 05:33
  • @shai, One major issue is that it doesn't look you registered `isEmailExistsValidator` actually as a [Directive](https://angular.io/api/core/Directive) and with providers of [NG_ASYNC_VALIDATORS](https://angular.io/api/forms/NG_ASYNC_VALIDATORS). Please see the official [documentation](https://angular.io/guide/form-validation#implementing-custom-async-validator) as well as the official [example](https://stackblitz.com/angular/jlpoknklpvl) and update your code accordingly. Then if you still have issues please update your question with the new code. You can't use a service as a directive. – Alexander Staroselsky Sep 05 '19 at 14:58

1 Answers1

0

Ideally, this should NOT happen.

Even on the assumption that your API throws some http error and you haven't explicitly handled failed http responses (using catchError), it is unlikely to reproduce the scenario that you have specified since asyncValidators get called on every change, so http obervable will be resubscribed on the subsequent input change.

Here is a working example - stackblitz

It'll be easy to help you if you can provide a stackblitz url where the issue can be reproduced.

Pankaj
  • 538
  • 4
  • 13
  • thanks for your answer! I found out recently that there was an HTTP interceptor that caches all http requests and makes sure that http requests repeated within a matter of seconds are not repeated –  Sep 06 '19 at 17:07