How to overwrite setTimeout before it reach the time set? - javascript

So I'm doing an autocomplete 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').autocomplete({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!

First, 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').autocomplete({source: s});
}
});
}

The other answers involving setTimeout() are simple and will work, but this is one of the few times when I would recommend 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 recommend 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 autocomplete so that the API is not called as soon as the user starts typing.
Here is the reference from autocomplete
minLength: The minimum number of characters a user must type before a search is performed
$( "#inputVendor" ).autocomplete({
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;

Related

Not understanding setInterval function

I am reading a project that I have to work and do additional work on, but I don't understand some interval trickery that has been done and not explained by the previous person. That's the code:
var intervalId;
var intervalIdtwo;
$(document).on('click', 'li.mention-individuals', function() {
clearInterval(loadTimer);
var otheridFromSearch = $(this).data('profileid');
var searchImage = $(this).find('img.search-image').attr('src');
var searchName = $(this).find('.mention-name').text();
$('.users-right-pro-pic img').attr('src', searchImage);
$('.users-right-pro-name').text(searchName);
$('.user-info').attr("data-otherid", otheridFromSearch);
xyz(useridd, otheridFromSearch, abc);
$.post('http://localhost/facebook/core/ajax/message.php', {
showmsg: otheridFromSearch,
yourid: useridForAjax
}, function(data) {
$('.msg-box').html(data);
$('.user-show').empty();
$('.top-msg-user-photo img').attr('src', searchImage);
$('.top-msg-user-name').text(searchName);
scrollItself();
})
if (!intervalId) {
intervalId = setInterval(function() {
loadMessageFromSearch(useridForAjax, otheridFromSearch);
}, 1000);
clearInterval(intervalIdtwo);
intervalIdtwo = null;
} else if (!intervalIdtwo) {
clearInterval(intervalId);
intervalId = null;
intervalIdtwo = setInterval(function() {
loadMessageFromSearch(useridForAjax, otheridFromSearch);
}, 1000);
} else {
alert('Nothing found');
}
})
function loadMessageFromSearch(useridForAjax, otheridFromSearch) {
var pastDataCount = $('.past-data-count').data('datacount'); //if no new data, the old messages will be shown
$.ajax({
type: "POST",
url: "http://localhost/facebook/core/ajax/message.php",
data: {
showmsg: otheridFromSearch,
yourid: useridForAjax
},
success: function(data) {
$('.msg-box').html(data);
}
})
$.post('http://localhost/facebook/core/ajax/message.php', {
dataCount: otheridFromSearch,
profileid: useridForAjax
}, function(data) {
if (pastDataCount == data) {
console.log('data is same');
} else {
scrollItself();
console.log('data is not same');
}
})
}
I generally get the code, but the Ifs section with the IntervalId and IntervalIdTwo - I have no clue what it does. Any tips or explanations would be greatly appreciated!
On the surface, the setInterval function is simple: it takes a function and a number n and calls the function (at most) every n milliseconds. It also returns a "handle" that allows you to cancel the repeated invocations by calling clearInterval with the handle.
For instance, here is a function that logs a string to the console:
function sayHello() {
console.log('hello!');
}
We can call it every second (1000 milliseconds) like so:
setInterval(sayHello, 1000);
(You can even try it out in your browser's dev. tools right now! It should print 'hello!' every second)
What if we want to stop printing 'hello!'? If we "hold onto" the return value, we can cancel the repeated invocations:
const handle = setInterval(sayHello, 1000);
(If you're curious, try printing handle!)
To cancel the process, call the clearInterval function with the handle:
clearInterval(handle);
A couple of notes:
In a lot of cases, it is a pain to define a separate function like sayHello, so we would instead use an "anonymous function", like:
setInterval(function() {
console.log('hello!');
}, 1000);
// or
setInterval(() => console.log('hello!'), 1000);
This underscores the fact that setInterval is a higher-order function: it takes another function as one of its arguments. This can take some getting used to, but with practice it becomes second nature.
Depending on how "busy" your browser is, the invocations may not take place at exactly the interval you specify. The delay may be longer than the number you provide, but never shorter (see 3. below for why).
if you really want to grok setInterval you will need an understanding of JavaScript's concurrency model.

Debounce function in Jquery?

Been looking for a debounce function or way to debounce in Jquery. The build up of animations can get super annoying.
Heres the code:
function fade() {
$('.media').hide();
$('.media').fadeIn(2000);
}
var debounce = false;
function colorChange() {
if (debounce) return;
debounce = true;
$('.centered').mouseenter(function() {
$('.centered').fadeTo('fast', .25);
});
$('.centered').mouseleave(function() {
$('.centered').fadeTo('fast', 1);
});
}
function colorChange2() {
$('.centered2').mouseenter(function() {
$('.centered2').fadeTo('fast', .25);
});
$('.centered2').mouseleave(function() {
$('.centered2').fadeTo('fast', 1);
});
}
function colorChange3() {
$('.centered3').mouseenter(function() {
$('.centered3').fadeTo('fast', .25);
});
$('.centered3').mouseleave(function() {
$('.centered3').fadeTo('fast', 1);
});
}
function closerFade() {
$('.closer').hide();
$('.closer').fadeIn(2000);
}
I wrapped those all in $(document).ready(function() {
Is there way to debounce??
I don´t like the idea to include a library just for a debounce function. You can just do:
var debounce = null;
$('#input').on('keyup', function(e){
clearTimeout(debounce );
debounce = setTimeout(function(){
$.ajax({url: 'someurl.jsp', data: {query: q}, type: 'GET'})
}, 100);
});
I would just include underscore.js in my project and use the debounce function that it contains. It works great. I've used it in multiple projects.
http://underscorejs.org/#debounce
debounce_.debounce(function, wait, [immediate]) Creates and returns a
new debounced version of the passed function which will postpone its
execution until after wait milliseconds have elapsed since the last
time it was invoked. Useful for implementing behavior that should only
happen after the input has stopped arriving. For example: rendering a
preview of a Markdown comment, recalculating a layout after the window
has stopped being resized, and so on.
At the end of the wait interval, the function will be called with the
arguments that were passed most recently to the debounced function.
Pass true for the immediate argument to cause debounce to trigger the
function on the leading instead of the trailing edge of the wait
interval. Useful in circumstances like preventing accidental
double-clicks on a "submit" button from firing a second time.
var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);

setTimeout function associated with a event

i want to be able to call my function of setTimeout when a user enter a number in my input after 1s.
But the problem i want that this event is called just once for example when a user enter 3 numbers like 200 in a time less than 1s.
My code below is called 3 time if a user enter 3 numbers like 200
$('input.amount').on('input.amount',function(e){
setTimeout(function() {
// code
}, 1000);
});
So i want that this code is called just once
You may be able to keep a variable that tells you if the user already typed a character. Then only trigger the function if the variable is not yet set. For example:
var started = false;
$('input.amount').on('input',function(e){
if(!started){
started = true;
setTimeout(function() {
// code
started = false;//to reset so that further typing will trigger again
}, 1000);
}
});
One approach I would take is to delay the execution till after 1000ms after the last input
var timer;
$('input.amount').on('input.amount', function (e) {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(function () {
// code
timer = undefined;
}, 1000);
});

Strange behavior with debounced/throttled function

I have a function that I need to call, every time a textbox value changes. However, it initializes an AJAX call, so I need to not run the script on every keystroke.
I wrote the following function as a proof of concept:
$(document).ready(function() {
var scheduledChange;
function triggerLinkChange(value, debounce) {
clearTimeout(scheduledChange);
scheduledChange = setTimeout(function(val) {
alert("value: "+val);
}(value), debounce);
}
$('input').keyup(function(){
triggerLinkChange($(this).val(),3000);
});
});
Unfortunately, the delay seems to not be working, properly. I'm not sure exactly what the issue is, as it appears to have a slight delay for the first call (maybe), but then fires with every keypress.
Any ideas?
You're calling the function that you declare in the timeout immediately, instead of passing it to the function.
However, it will actually work without binding or passing value to the function, because the variable is in scope anyway:
scheduledChange = setTimeout(function() {
alert("value: " + value);
}, debounce);
Here's an example: http://jsfiddle.net/RbLRu/
Seems too complicated ?
$('input').keyup(function(){
var self = this;
clearTimeout( $(this).data('timer') );
$(this).data('timer', setTimeout(function(){
// do ajax, 3 seconds seems like lot here
$.get('url', {value : self.value}, callback);
}, 3000));
});
A much simpler way is to have a variable like this (pseudo-code because I am just typing it out here):
var myTrigger;
$('input').keyup(function(){
// Cancel the countdown to do the ajax
window.clearTimeout(myTrigger);
// Now reset it to trigger in 3 seconds unless another key is pressed
myTrigger = window.setTimeout(function () { DoAjax(); }, 3000);
}
});

How to delay the .keyup() handler until the user stops typing?

I’ve got a search field. Right now it searches for every keyup. So if someone types “Windows”, it will make a search with AJAX for every keyup: “W”, “Wi”, “Win”, “Wind”, “Windo”, “Window”, “Windows”.
I want to have a delay, so it only searches when the user stops typing for 200 ms.
There is no option for this in the keyup function, and I have tried setTimeout, but it didn’t work.
How can I do that?
I use this small function for the same purpose, executing a function after the user has stopped typing for a specified amount of time or in events that fire at a high rate, like resize:
function delay(callback, ms) {
var timer = 0;
return function() {
var context = this, args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
callback.apply(context, args);
}, ms || 0);
};
}
// Example usage:
$('#input').keyup(delay(function (e) {
console.log('Time elapsed!', this.value);
}, 500));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label for="input">Try it:
<input id="input" type="text" placeholder="Type something here..."/>
</label>
How it works:
The delay function will return a wrapped function that internally handles an individual timer, in each execution the timer is restarted with the time delay provided, if multiple executions occur before this time passes, the timer will just reset and start again.
When the timer finally ends, the callback function is executed, passing the original context and arguments (in this example, the jQuery's event object, and the DOM element as this).
UPDATE 2019-05-16
I have re-implemented the function using ES5 and ES6 features for modern environments:
function delay(fn, ms) {
let timer = 0
return function(...args) {
clearTimeout(timer)
timer = setTimeout(fn.bind(this, ...args), ms || 0)
}
}
The implementation is covered with a set of tests.
For something more sophisticated, give a look to the jQuery Typewatch plugin.
If you want to search after the type is done use a global variable to hold the timeout returned from your setTimout call and cancel it with a clearTimeout if it hasn't yet happend so that it won't fire the timeout except on the last keyup event
var globalTimeout = null;
$('#id').keyup(function(){
if(globalTimeout != null) clearTimeout(globalTimeout);
globalTimeout =setTimeout(SearchFunc,200);
}
function SearchFunc(){
globalTimeout = null;
//ajax code
}
Or with an anonymous function :
var globalTimeout = null;
$('#id').keyup(function() {
if (globalTimeout != null) {
clearTimeout(globalTimeout);
}
globalTimeout = setTimeout(function() {
globalTimeout = null;
//ajax code
}, 200);
}
Another slight enhancement on CMS's answer. To easily allow for separate delays, you can use the following:
function makeDelay(ms) {
var timer = 0;
return function(callback){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
};
If you want to reuse the same delay, just do
var delay = makeDelay(250);
$(selector1).on('keyup', function() {delay(someCallback);});
$(selector2).on('keyup', function() {delay(someCallback);});
If you want separate delays, you can do
$(selector1).on('keyup', function() {makeDelay(250)(someCallback);});
$(selector2).on('keyup', function() {makeDelay(250)(someCallback);});
You could also look at underscore.js, which provides utility methods like debounce:
var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);
Explanation
Use a variable to store the timeout function. Then use clearTimeout() to clear this variable of any active timeout functions, and then use setTimeout() to set the active timeout function again. We run clearTimeout() first, because if a user is typing "hello", we want our function to run shortly after the user presses the "o" key (and not once for each letter).
Working Demo
Super simple approach, designed to run a function after a user has finished typing in a text field...
$(document).ready(function(e) {
var timeout;
var delay = 2000; // 2 seconds
$('.text-input').keyup(function(e) {
$('#status').html("User started typing!");
if(timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(function() {
myFunction();
}, delay);
});
function myFunction() {
$('#status').html("Executing function for user!");
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Status: <span id="status">Default Status</span><br>
<textarea name="text-input" class="text-input"></textarea>
Based on the answer of CMS, I made this :
Put the code below after include jQuery :
/*
* delayKeyup
* http://code.azerti.net/javascript/jquery/delaykeyup.htm
* Inspired by CMS in this post : http://stackoverflow.com/questions/1909441/jquery-keyup-delay
* Written by Gaten
* Exemple : $("#input").delayKeyup(function(){ alert("5 secondes passed from the last event keyup."); }, 5000);
*/
(function ($) {
$.fn.delayKeyup = function(callback, ms){
var timer = 0;
$(this).keyup(function(){
clearTimeout (timer);
timer = setTimeout(callback, ms);
});
return $(this);
};
})(jQuery);
And simply use like this :
$('#input').delayKeyup(function(){ alert("5 secondes passed from the last event keyup."); }, 5000);
Careful : the $(this) variable in the function passed as a parameter does not match input
jQuery:
var timeout = null;
$('#input').keyup(function() {
clearTimeout(timeout);
timeout = setTimeout(() => {
console.log($(this).val());
}, 1000);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<input type="text" id="input" placeholder="Type here..."/>
Pure Javascript:
let input = document.getElementById('input');
let timeout = null;
input.addEventListener('keyup', function (e) {
clearTimeout(timeout);
timeout = setTimeout(function () {
console.log('Value:', input.value);
}, 1000);
});
<input type="text" id="input" placeholder="Type here..."/>
Delay Multi Function Calls using Labels
This is the solution i work with. It will delay the execution on ANY function you want. It can be the keydown search query, maybe the quick click on previous or next buttons ( that would otherwise send multiple request if quickly clicked continuously , and be not used after all). This uses a global object that stores each execution time, and compares it with the most current request.
So the result is that only that last click / action will actually be called, because those requests are stored in a queue, that after the X milliseconds is called if no other request with the same label exists in the queue!
function delay_method(label,callback,time){
if(typeof window.delayed_methods=="undefined"){window.delayed_methods={};}
delayed_methods[label]=Date.now();
var t=delayed_methods[label];
setTimeout(function(){ if(delayed_methods[label]!=t){return;}else{ delayed_methods[label]=""; callback();}}, time||500);
}
You can set your own delay time ( its optional, defaults to 500ms). And send your function arguments in a "closure fashion".
For example if you want to call the bellow function:
function send_ajax(id){console.log(id);}
To prevent multiple send_ajax requests, you delay them using:
delay_method( "check date", function(){ send_ajax(2); } ,600);
Every request that uses the label "check date" will only be triggered if no other request is made in the 600 miliseconds timeframe. This argument is optional
Label independency (calling the same target function) but run both:
delay_method("check date parallel", function(){send_ajax(2);});
delay_method("check date", function(){send_ajax(2);});
Results in calling the same function but delay them independently because of their labels being different
If someone like to delay the same function, and without external variable he can use the next script:
function MyFunction() {
//Delaying the function execute
if (this.timer) {
window.clearTimeout(this.timer);
}
this.timer = window.setTimeout(function() {
//Execute the function code here...
}, 500);
}
This function extends the function from Gaten's answer a bit in order to get the element back:
$.fn.delayKeyup = function(callback, ms){
var timer = 0;
var el = $(this);
$(this).keyup(function(){
clearTimeout (timer);
timer = setTimeout(function(){
callback(el)
}, ms);
});
return $(this);
};
$('#input').delayKeyup(function(el){
//alert(el.val());
// Here I need the input element (value for ajax call) for further process
},1000);
http://jsfiddle.net/Us9bu/2/
I'm surprised that nobody mention the problem with multiple input in CMS's very nice snipped.
Basically, you would have to define delay variable individually for each input. Otherwise if sb put text to first input and quickly jump to other input and start typing, callback for the first one WON'T be called!
See the code below I came with based on other answers:
(function($) {
/**
* KeyUp with delay event setup
*
* #link http://stackoverflow.com/questions/1909441/jquery-keyup-delay#answer-12581187
* #param function callback
* #param int ms
*/
$.fn.delayKeyup = function(callback, ms){
$(this).keyup(function( event ){
var srcEl = event.currentTarget;
if( srcEl.delayTimer )
clearTimeout (srcEl.delayTimer );
srcEl.delayTimer = setTimeout(function(){ callback( $(srcEl) ); }, ms);
});
return $(this);
};
})(jQuery);
This solution keeps setTimeout reference within input's delayTimer variable. It also passes reference of element to callback as fazzyx suggested.
Tested in IE6, 8(comp - 7), 8 and Opera 12.11.
This worked for me where I delay the search logic operation and make a check if the value is same as entered in text field. If value is same then I go ahead and perform the operation for the data related to search value.
$('#searchText').on('keyup',function () {
var searchValue = $(this).val();
setTimeout(function(){
if(searchValue == $('#searchText').val() && searchValue != null && searchValue != "") {
// logic to fetch data based on searchValue
}
else if(searchValue == ''){
// logic to load all the data
}
},300);
});
Delay function to call up on every keyup.
jQuery 1.7.1 or up required
jQuery.fn.keyupDelay = function( cb, delay ){
if(delay == null){
delay = 400;
}
var timer = 0;
return $(this).on('keyup',function(){
clearTimeout(timer);
timer = setTimeout( cb , delay );
});
}
Usage: $('#searchBox').keyupDelay( cb );
From ES6, one can use arrow function syntax as well.
In this example, the code delays keyup event for 400ms after users finish typeing before calling searchFunc make a query request.
const searchbar = document.getElementById('searchBar');
const searchFunc = // any function
// wait ms (milliseconds) after user stops typing to execute func
const delayKeyUp = (() => {
let timer = null;
const delay = (func, ms) => {
timer ? clearTimeout(timer): null
timer = setTimeout(func, ms)
}
return delay
})();
searchbar.addEventListener('keyup', (e) => {
const query = e.target.value;
delayKeyUp(() => {searchFunc(query)}, 400);
})
Updated Typescript version:
const delayKeyUp = (() => {
let timer: NodeJS.Timeout;
return (func: Function, ms: number) => {
timer ? clearTimeout(timer) : null;
timer = setTimeout(() => func(), ms);
};
})();
This is a solution along the lines of CMS's, but solves a few key issues for me:
Supports multiple inputs, delays can run concurrently.
Ignores key events that didn't changed the value (like Ctrl, Alt+Tab).
Solves a race condition (when the callback is executed and the value already changed).
var delay = (function() {
var timer = {}
, values = {}
return function(el) {
var id = el.form.id + '.' + el.name
return {
enqueue: function(ms, cb) {
if (values[id] == el.value) return
if (!el.value) return
var original = values[id] = el.value
clearTimeout(timer[id])
timer[id] = setTimeout(function() {
if (original != el.value) return // solves race condition
cb.apply(el)
}, ms)
}
}
}
}())
Usage:
signup.key.addEventListener('keyup', function() {
delay(this).enqueue(300, function() {
console.log(this.value)
})
})
The code is written in a style I enjoy, you may need to add a bunch of semicolons.
Things to keep in mind:
A unique id is generated based on the form id and input name, so they must be defined and unique, or you could adjust it to your situation.
delay returns an object that's easy to extend for your own needs.
The original element used for delay is bound to the callback, so this works as expected (like in the example).
Empty value is ignored in the second validation.
Watch out for enqueue, it expects milliseconds first, I prefer that, but you may want to switch the parameters to match setTimeout.
The solution I use adds another level of complexity, allowing you to cancel execution, for example, but this is a good base to build on.
Combining CMS answer with Miguel's one yields a robust solution allowing concurrent delays.
var delay = (function(){
var timers = {};
return function (callback, ms, label) {
label = label || 'defaultTimer';
clearTimeout(timers[label] || 0);
timers[label] = setTimeout(callback, ms);
};
})();
When you need to delay different actions independently, use the third argument.
$('input.group1').keyup(function() {
delay(function(){
alert('Time elapsed!');
}, 1000, 'firstAction');
});
$('input.group2').keyup(function() {
delay(function(){
alert('Time elapsed!');
}, 1000, '2ndAction');
});
Building upon CMS's answer here's new delay method which preserves 'this' in its usage:
var delay = (function(){
var timer = 0;
return function(callback, ms, that){
clearTimeout (timer);
timer = setTimeout(callback.bind(that), ms);
};
})();
Usage:
$('input').keyup(function() {
delay(function(){
alert('Time elapsed!');
}, 1000, this);
});
If you want to do something after a period of time and reset that timer after a specific event like keyup, the best solution is made with clearTimeout and setTimeout methods:
// declare the timeout variable out of the event listener or in the global scope
var timeout = null;
$(".some-class-or-selector-to-bind-event").keyup(function() {
clearTimeout(timout); // this will clear the recursive unneccessary calls
timeout = setTimeout(() => {
// do something: send an ajax or call a function here
}, 2000);
// wait two seconds
});
Use
mytimeout = setTimeout( expression, timeout );
where expression is the script to run and timeout is the time to wait in milliseconds before it runs - this does NOT hault the script, but simply delays execution of that part until the timeout is done.
clearTimeout(mytimeout);
will reset/clear the timeout so it does not run the script in expression (like a cancel) as long as it has not yet been executed.
Based on the answer of CMS, it just ignores the key events that doesn't change value.
var delay = (function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
var duplicateFilter=(function(){
var lastContent;
return function(content,callback){
content=$.trim(content);
if(content!=lastContent){
callback(content);
}
lastContent=content;
};
})();
$("#some-input").on("keyup",function(ev){
var self=this;
delay(function(){
duplicateFilter($(self).val(),function(c){
//do sth...
console.log(c);
});
}, 1000 );
})
User lodash javascript library and use _.debounce function
changeName: _.debounce(function (val) {
console.log(val)
}, 1000)
Use the bindWithDelay jQuery plugin:
element.bindWithDelay(eventType, [ eventData ], handler(eventObject), timeout, throttle)
var globalTimeout = null;
$('#search').keyup(function(){
if(globalTimeout != null) clearTimeout(globalTimeout);
globalTimeout =setTimeout(SearchFunc,200);
});
function SearchFunc(){
globalTimeout = null;
console.log('Search: '+$('#search').val());
//ajax code
};
Here is a suggestion I have written that takes care of multiple input in your form.
This function gets the Object of the input field, put in your code
function fieldKeyup(obj){
// what you want this to do
} // fieldKeyup
This is the actual delayCall function, takes care of multiple input fields
function delayCall(obj,ms,fn){
return $(obj).each(function(){
if ( typeof this.timer == 'undefined' ) {
// Define an array to keep track of all fields needed delays
// This is in order to make this a multiple delay handling
function
this.timer = new Array();
}
var obj = this;
if (this.timer[obj.id]){
clearTimeout(this.timer[obj.id]);
delete(this.timer[obj.id]);
}
this.timer[obj.id] = setTimeout(function(){
fn(obj);}, ms);
});
}; // delayCall
Usage:
$("#username").on("keyup",function(){
delayCall($(this),500,fieldKeyup);
});
Take a look at the autocomplete plugin. I know that it allows you to specify a delay or a minimum number of characters. Even if you don't end up using the plugin, looking through the code will give you some ideas on how to implement it yourself.
Well, i also made a piece of code for limit high frequency ajax request cause by Keyup / Keydown. Check this out:
https://github.com/raincious/jQueue
Do your query like this:
var q = new jQueue(function(type, name, callback) {
return $.post("/api/account/user_existed/", {Method: type, Value: name}).done(callback);
}, 'Flush', 1500); // Make sure use Flush mode.
And bind event like this:
$('#field-username').keyup(function() {
q.run('Username', this.val(), function() { /* calling back */ });
});
Saw this today a little late but just want to put this here in case someone else needed. just separate the function to make it reusable. the code below will wait 1/2 second after typing stop.
var timeOutVar
$(selector).on('keyup', function() {
clearTimeout(timeOutVar);
timeOutVar= setTimeout(function(){ console.log("Hello"); }, 500);
});
// Get an global variable isApiCallingInProgress
// check isApiCallingInProgress
if (!isApiCallingInProgress) {
// set it to isApiCallingInProgress true
isApiCallingInProgress = true;
// set timeout
setTimeout(() => {
// Api call will go here
// then set variable again as false
isApiCallingInProgress = false;
}, 1000);
}

Categories