Jens Törnell
Jens Törnell

Reputation: 24778

Javascript search delay and collect input from eventlistener

I have a simple input box. When I write something, I want it to be delayed. The problem I have is after the delay when writing characters very fast it calls the console.log multiple times.

What happened now

I type a and wait. Then I type b c d fast and wait. Then e f fast and wait. It catches up which I don't want. I want it to collect what I type, but not output it until the delay is done.

a
.
.
.
b c d
b c d
b c d
.
.
.
e f
e f

What I want to happen

a
.
.
.
b c d
.
.
.
e f

var searchtimer;

window.addEventListener("DOMContentLoaded", () => {
  document.querySelector("#search").addEventListener("input", (e) => {
    searchtimer = setTimeout(() => {
      console.log(e.target.value);
      clearTimeout(searchtimer);
    }, 1000);
  });
});
<input id="search" type="text">

Upvotes: 6

Views: 3853

Answers (2)

Ravi Teja Muddada
Ravi Teja Muddada

Reputation: 391

Solution with step by step explanation

So you need to debounce.

The below code shows how a function is executed only when the time difference between 2 keystrokes is at least 2 seconds.

let count=0;

//If we call this directly from the HTML, the function will be 
// fired for every click, which hinders the performance
let myFunction =()=>{
  document.querySelector("#demo").innerHTML = "Hello World "+ ++count ;
}

//So we'll call this debouncing wrapper function from the HTML instead
let myFunc=letsDebounce(myFunction,2000);

//The wrapper calls setTimeout to execute its argument fn after
// the specified delay, but if the triggering event fires again
// before the setTimeout duration finishes, then the timer gets reset
// so the previous call is ignored
function letsDebounce(fn,d){
  let timer;
  return function(){
    clearTimeout(timer);
    timer=setTimeout(fn,d);
  }
}
<button onclick="myFunc()">Debounce</button>

<p id="demo"></p>

Upvotes: 2

Nguyễn Văn Phong
Nguyễn Văn Phong

Reputation: 14228

Your expected behavior looks like debounce.

It seems to me that you should clearTimeout before creating the new one.

var searchtimer;
window.addEventListener("DOMContentLoaded", () => {
  document.querySelector("#search").addEventListener("input", (e) => {
    clearTimeout(searchtimer); // <--- The solution is here
    searchtimer = setTimeout(() => {
      console.log(e.target.value);
    }, 1000);
  });
});
<input id="search" type="text">


More detailed explanation:

  • It is basically a way for eliminating unwanted signals from an input. So if the defined duration hasn't passed, the previous action should be eliminated by clearTimeout(searchtimer);
  • Keynote: The operator keeps track of the most recent value.

Read post "throttleTime vs debounceTime in RxJS" to understand in detail.

Upvotes: 7

Related Questions