0

Currently, I am working on Angular 4 app. In my component Html, I have one textbox. Whenever user first type anything I want to make an API call to get some data.

The issue is if User type 'A' then it is working fine and calling API. But when user type "ABC" it is making API call 3 times. Instead of making API call for every letter, only one call should be made.

Please suggest any solution.

Component's HTML :

<input id="inputbox" (keyup)="keyUp($event)"/>

Component :

data: string[]

keyUp(event: any) {
this.loadDataApiCall();
}

loadDataApiCall() {
// calling api to load data.
 //fill data into 
}

Can I solve this issue with help of RXjs in angular 4

xpy
  • 5,481
  • 3
  • 29
  • 48
  • check out this question which is very similar to what you want to do https://stackoverflow.com/questions/41935424/how-to-achieve-a-debounce-service-on-input-keyup-event-in-angular2-with-rxjs – Fan Cheung Oct 16 '17 at 08:17

7 Answers7

2
 Observable.fromEvent(yourDomElement, 'keyup').auditTime(100).subscribe(()=>{
      doSomething();
    });
Coco
  • 457
  • 1
  • 3
  • 14
1

You should probably add a timeout to your call and clear it every time it is triggered so only the last call is called.

data: string[]

keyUp(event: any) {
    window.clearTimeout(window.apiCallTimeout);
    window.apiCallTimeout = window.setTimeout(this.loadDataApiCall, 100);
}

loadDataApiCall() {
// calling api to load data.
 //fill data into 
}

This means of course that the call will be done 100ms after the user stops typing. Also if he types "a" and after a while he types "bc", then two calls will be made. Of course you can increase the delay to meet your requirements.

xpy
  • 5,481
  • 3
  • 29
  • 48
0

If you only want one API call you can use the blur event, which is emitted when the control loses focus:

<input id="inputbox" (blur)="keyUp($event)"/>
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
0

Try this:

keyUp(event: any) {
this.loadDataApiCall();
event.stopImmediatePropagation();
}
Abdus Sattar Bhuiyan
  • 3,016
  • 4
  • 38
  • 72
0

the right way to implement this is by registering the event and calling the API after sometime while saving the latest value and checking that the last registered value matches the latest registered value

so in your keyup

keyUp(event: any) {
  this.latestValue = event.target.value;
  this.registerApiCall(event.target.value);
}

register func

 registerApiCall(value){
      setTimeout(this.loadDataApiCall.bind(this), 500, value)
    }

api call

loadDataApiCall(value) {
  if (this.latestValue == value ){
    // calling api to load data.
    //fill data into 
  }
}

see working example in this plnk

EDIT:

Observable.fromEvent(yourDomElement, 'keyup').auditTime(100).subscribe(()=>{ doSomething(); });

by 陈杨华 is the RxJs implementation that looks much better, and here is a working plnkr

bresleveloper
  • 5,940
  • 3
  • 33
  • 47
0

If you're willing to change your form to Reactive Forms this would be extremely easy

this.form.get("input").valueChanges.debounceTime(1000).subscribe((value) => {});

Reactive Forms gives you access to observables of value changes and status changes. We're basically subscribing to that observable which emits the value any time it changes and we add a delay of one second so that if the user is still typing and changing the value then it will not execute the code in our subscribe.

Christian
  • 2,676
  • 3
  • 15
  • 25
0
@Component({
  selector: 'my-app',
  template: `
    <div>
      <input type="text" (keyup)='keyUp.next($event)'>
    </div>
  ,
})
export class App {
  name:string;

  public keyUp = new Subject<string>();

  constructor() {
    const subscription = this.keyUp
      .map(event => event.target.value)
      .debounceTime(1000)
      .distinctUntilChanged()
      .flatMap(search => Observable.of(search).delay(500))
      .subscribe(console.log);
  }
}