blixenkrone
blixenkrone

Reputation: 407

RxJs methods doesn't limit API calls as expected - for every key input, there's a call to the API

I get a response from my API that's either "Exists" or "NotFound" according to, if a username is already in use. I figured i could use RxJs to limit the calls with the debounceTime and distinctUntilChanged methods, but it seems as they are not doing their job. Fairly new to RxJs.

Output:

As you can see in the console, an API call is made 15 times, as that is the length of the string.

Console output

Expected behavior:

The user types in the desired username, my validations (spinner, api calls etc.) is made, and the debounce time is making an API call once every 600 ms., if the input value changes during the timeout.

According to docs:

As per the docs, debounceTime(n) is supposed to discard previous pending delayed emissions if a new value arrives on the source.

I receive the Observable from the form input, and call the valueChanges property:

Emits an event every time the value of the control changes, in the UI or programmatically.

Imports:

import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';

TS:

 validateDisplayName(displayName) {
    this.vNickLoading = true;
    this.isUserTaken = '';
    this.displayName = displayName.toLowerCase();
    const dName = this.accountForm.controls['displayName'];
    console.log(dName)
    dName.valueChanges
      .distinctUntilChanged()
      .debounceTime(600)
      .subscribe(dName => {
        this.displayName = dName;
        console.log(this.displayName)
        if (displayName.length < 3) {
          return;
        } else {
          this.editProfileSrv.validateUserName(this.displayName)
            .subscribe(data => {
              console.log(data)
              this.isUserTaken = data.statusResponse;
              if (this.isUserTaken === 'Exists' || this.isUserTaken === 'NotFound') {
                this.vNickLoading = false;
              }
            },
          error => console.log(error))
        }
      })
  }

HTML:

<input #dName type="text" class="form-control" placeholder="Username" formControlName="displayName" (keyup)="validateDisplayName(displayName)"
                  [(ngModel)]="displayName" required>

Upvotes: 1

Views: 567

Answers (1)

Baris Bikmaz
Baris Bikmaz

Reputation: 401

Your problem is that you subscribe to valueChanges each time you enter a sth. You've to extract the valueChanges subscription to ngOnInit.

ngOnInit() {
   const displayName = this.accountForm.controls['displayName'];

  displayName.valueChanges
    .distinctUntilChanged()
    .debounceTime(600)
    .subscribe(dName => {
      this.displayName = dName;

      this.vNickLoading = true;
      this.isUserTaken = '';
      dName = dName.toLowerCase();

      if (dName.length < 3) {
        return;
      } else {
        this.editProfileSrv.validateUserName(dName)
          .subscribe(data => {
            console.log(data)
            this.isUserTaken = data.statusResponse;
            if (this.isUserTaken === 'Exists' || this.isUserTaken === 'NotFound') {
              this.vNickLoading = false;
            }
          },
        error => console.log(error))
      }
    });
}

and html

<input type="text" class="form-control" placeholder="Username" formControlName="displayName" required>

Upvotes: 2

Related Questions