Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript timeout fires 3 times instead of once (clearTimeout is not working ?)

I want to fire an ajax action when user make a pause in typing (instead of after every keypressed). So I made something like this:

When the user stops typing after 3 secs of being idle function done is to be executed ... (it is - but why 3 times for long phrases - I would expect it to run only once since I clear timeout after every keydown). What is the problem ?

var timer; 
var interval = 3000; 
$('#inp').keyup(function() {
  timer = setTimeout(done, interval); 
}); 

$('#inp').keydown(function() {
  clearTimeout(timer)  
}); 

function done() {
  console.log('ajax'); 
}

Working example on jsfiddle : http://jsfiddle.net/vtwVH/

like image 986
user1983515 Avatar asked Feb 01 '13 12:02

user1983515


3 Answers

When you type, you may sometimes press down another key before releasing the first. You may not notice this, particularly if you're typing a long phrase. In that case, the order of events is not down up down up but down down up up, and so two timeouts will be set.

It is more consistent to clear the timeout just before setting it (in the same event handler).

like image 160
pimvdb Avatar answered Oct 12 '22 23:10

pimvdb


The Problem is you are overwriting the timer variable in your keydown event.

So if you press another key before the Timout gets cleared e.g keep holding a key

The reference to the timeOut is lost and you cannot clear it again.

To fix this you could just clear and set the Timer in the keyUp event like

var timer; 
var interval = 3000; 


$('#inp').keyup(function(e){ 
    if(timer) {
        clearTimeout(timer);
    }
    timer = setTimeout(done, interval); 

}); 

function done() {
    console.log('ajax'); 
}

Heres a working fiddle

like image 45
Moritz Roessler Avatar answered Oct 12 '22 22:10

Moritz Roessler


The events seem to not follow strict sequential rules, second keydown comes earlier than first keyup, so the timer gets initialized multiple times.

Try this mod:

$('#inp').keyup(function(){
  clearTimeout(timer);
  timer = setTimeout(done, interval); 
}); 
like image 32
kms Avatar answered Oct 12 '22 23:10

kms