Clear timeout with every function call Angular2 RxJS

8.5k Views Asked by At

I have a http request which is being fired if user enters at least 4 characters inside the input and fires everytime he changes it's content (adding/removing letters). I want to add a timeout, that if user starts typing characters, the function will wait 1 second until it fires the request, to avoid a lot of requests when user is typing quickly. My attempt:

if (this.pointName.length >= 3) {
  let timer = function() {
    this.http.get(`./points.json`)
        .subscribe(res => {
            this.pointsArray = res.json();
        });
    };
clearTimeout(timer); 
setTimeout(timer,1000);

My idea was to clear the timeout on every keyup event and set it once again. But unfortunately it gives me an error, that `Argument of type '() => void' is not assignable to parameter of type 'number'.

Is there any way to do it more efficientely? Maybe using RxJS? Anyways, I'm looking for a working solution. Thank you in advance.

HTML

 <input type="text" id="searchInput" placeholder="Point name"(keyup)="getPoints()">
3

There are 3 best solutions below

5
On BEST ANSWER

Why dont use debounceTime(500) instead of setTimeout.

https://www.learnrxjs.io/operators/filtering/debouncetime.html

0
On

First of all, you'd better use Debounce operator in RxJS. And the problem in your code is that you should pass the timer_id into clearTimeout instead of the function.

if (this.pointName.length >= 3) {
  let timer = function() {
    this.http.get(`./points.json`)
        .subscribe(res => {
            this.pointsArray = res.json();
        });
    };
let timer_id = undefined;
clearTimeout(timer_id); 
timer_id = setTimeout(timer,1000);
0
On

Try this:

Create an RxJS Subject as a new member variable of your component

searchTerm$ = new Subject<string>();

In your component's ngOnInit method, set up your observable,

ngOnInit() {
  this.searchTerm$
      .filter( value => value.length >= 3)
      .debounceTime(1000)
      .switchMap( val => {
         return this.http.get('./points.json')
                         .map(result => result.json());
       })
      .subscribe(result => .... // do what you want with the response );
} 

In your HTML, change your keyup event binding to submit your input field's value

 <input type="text" id="searchInput" placeholder="Point name"(keyup)="getPoints(this.value)">

Then in your component's getPoints method,send a value into your subject$

getPoints(value) {
  this.subject$.next(value);
}

Basically, the observable you're creating does several things:

 searchTerm$
  .filter( value => value.length >= 3)   // 1 filter out search terms that are shorter than 3 characters
  .debounceTime(1000)                    // 2. only send events after no event comes for 1 sec
  .switchMap( val => {                    // 3. convert your value to the result of your http request
     return this.http.get('./points.json')
                     .map(result => result.json());
   })
  .subscribe(result => .... // do what you want with the response );