Javascript search delay and collect input from eventlistener

Viewed 916

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">

2 Answers

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.

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>

Related