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">
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">
Share
Improve this question
edited Mar 8, 2021 at 12:58
Nguyễn Văn Phong
14.2k19 gold badges46 silver badges63 bronze badges
asked Mar 8, 2021 at 12:41
Jens TörnellJens Törnell
24.8k46 gold badges130 silver badges223 bronze badges
5
- 1 Check this out. – DontVoteMeDown Commented Mar 8, 2021 at 12:48
-
1
@DontVoteMeDown Yes, OPs code starts a new timeout for every
input
event, but OP doesn't need "another timer to get the input end". – Andreas Commented Mar 8, 2021 at 12:50 - 1 Clear the timeout before you create a new one and it should work as expected (clearing the timeout when the timeout already happended doesn't make that much sense...) – Andreas Commented Mar 8, 2021 at 12:50
- @Andreas yeah you're right, its the same thing. – DontVoteMeDown Commented Mar 8, 2021 at 12:51
- @Andreas Yes, that was it! – Jens Törnell Commented Mar 8, 2021 at 12:59
2 Answers
Reset to default 7Your 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>