So I'm doing an autoplete search using jquery. I have to set a delay before executing the ajax function because I don't want to hammer my server with calls every time I type on a textbox. Here is my code:
function searchVendor() {
setTimeout(searchVendor2, 5000);
}
function searchVendor2() {
var search = $('#inputVendor').val();
$.ajax({
type: 'POST',
url: '/getVendors',
data: {search: search},
dataType: 'json',
success: function(s) {
$('#inputVendor').autoplete({source: s});
}
});
}
so the function searchVendor
is executed onkeyup
<input type="text" class="form-control input-sm" id="inputVendor" onkeyup="searchVendor()">
If I type 3 characters (ex. sas) then the function searchVendor2
is executed 3 times. The 5 seconds delay works but it didn't stop and overwrite the previous setTimeout
.
What I want to happen is, if I type a character on the textbox it will be executed after 5 seconds, BUT! if a new character is typed before the 5 seconds, setTimeout
is reset again to 5 seconds. As long as the user is typing on the textbox the setTimeout
is reset to 5 seconds and it will ONLY be executed if the 5 seconds elapsed without the user typing again.
Thanks to those who can help!
So I'm doing an autoplete search using jquery. I have to set a delay before executing the ajax function because I don't want to hammer my server with calls every time I type on a textbox. Here is my code:
function searchVendor() {
setTimeout(searchVendor2, 5000);
}
function searchVendor2() {
var search = $('#inputVendor').val();
$.ajax({
type: 'POST',
url: '/getVendors',
data: {search: search},
dataType: 'json',
success: function(s) {
$('#inputVendor').autoplete({source: s});
}
});
}
so the function searchVendor
is executed onkeyup
<input type="text" class="form-control input-sm" id="inputVendor" onkeyup="searchVendor()">
If I type 3 characters (ex. sas) then the function searchVendor2
is executed 3 times. The 5 seconds delay works but it didn't stop and overwrite the previous setTimeout
.
What I want to happen is, if I type a character on the textbox it will be executed after 5 seconds, BUT! if a new character is typed before the 5 seconds, setTimeout
is reset again to 5 seconds. As long as the user is typing on the textbox the setTimeout
is reset to 5 seconds and it will ONLY be executed if the 5 seconds elapsed without the user typing again.
Thanks to those who can help!
Share Improve this question edited Jul 28, 2019 at 5:15 MarredCheese 20.8k12 gold badges107 silver badges103 bronze badges asked May 25, 2017 at 5:45 Julio de LeonJulio de Leon 1,2125 gold badges15 silver badges32 bronze badges 2-
you can give
minLength
option so that the search will take place only after user enters minimum chars. EG:minLength: 3
– Sravan Commented May 25, 2017 at 5:50 - I'm not sure of I can say this but doesn't this defeat the autoplete purpose? I think it would be better to use the feature given with the autoplete such min length. – Ossama Commented May 25, 2017 at 7:49
6 Answers
Reset to default 9First, you need to save your timeout id in a global variable, or in a variable that can be accessed later when the function is called again.
Now, whenever your function is called, first you clear that timeout if it exists. Thus you clear any pre-existing timeouts and set a new one every time the function is called.
var myTimeout;
function searchVendor() {
clearTimeout(myTimeout);
myTimeout = setTimeout(searchVendor2, 5000);
}
function searchVendor2() {
var search = $('#inputVendor').val();
$.ajax({
type: 'POST',
url: '/getVendors',
data: {search: search},
dataType: 'json',
success: function(s) {
$('#inputVendor').autoplete({source: s});
}
});
}
The other answers involving setTimeout()
are simple and will work, but this is one of the few times when I would remend using a utility library as they can go a few steps further in a way that is noticeable to the user.
It is also important that we avoid re-inventing the wheel. And in this case, what you want is a debounce or throttle function to limit the number of times your handler gets executed within a given time span. The good libraries also accept options to tweak when exactly your handler gets run, which can affect the responsiveness of your app.
Read more about debouncing and throttling.
For your use case, I would remend Lodash's _.throttle()
with both leading
and trailing
options set to true
. This will ensure that long entries of text will still get some intermediate results, while also getting results as fast as possible (not having to wait for a timer the first time around) and still guaranteeing that the final keystroke will trigger a new result, which not all debounce settings would do.
const handler = (evt) => {
console.log('I will talk to the server.');
};
const throttled = _.throttle(handler, 500, {
leading : true,
trailing : true
});
Then register the throttled function as the event listener.
<input type="text" class="form-control input-sm" id="inputVendor" onkeyup="throttled()">
You must clear the timeout when you want to stop it. Instead of just doing this:
var timeoutId;
function searchVendor() {
timeoutId = setTimeout(searchVendor2, 5000);
}
you should add clearTimeout(timeoutId);
, like this:
var timeoutId;
function searchVendor() {
clearTimeout(timeoutId);
timeoutId = setTimeout(searchVendor2, 5000);
}
You can use minLength
of autoplete
so that the API is not called as soon as the user starts typing.
Here is the reference from autoplete
minLength: The minimum number of characters a user must type before a search is performed
$( "#inputVendor" ).autoplete({
minLength: 3
});
If you want on every keypress, as other answers suggested, you can use clearTimeout
to remove the old timeout.
var timeout;
function searchVendor() {
clearTimeout(timeout);
timeout = setTimeout(searchVendor2, 5000);
}
The setTimeout
and setInterval
functions can be stopped using clearTimeout
or clearInterval
functions, passing the unique identifier generated by the first ones. For example, here you have a small code that helps you to understand this:
var delay;
document.addEventListener("mousemove", function () {
callSetTimeout();
});
function callSetTimeout () {
if (!isNaN(delay)) { clearTimeout(delay); }
delay = setTimeout(function () {
console.log("do something");
}, 5000);
}
I change the timeout but I check with interval
var goal={
cb: cb
, timeout: (+new Date())+60000 //one minute from now
, setInterval(function(){
if((+new Date())>goal.timeout){cb();}
})
};
Now I want to increase, decrease or reset the timeout?
goal.timeout-=1000;
goal.timeout+=1000;
goal.timeout=60000;