views:

265

answers:

7

I have a text box on a web page, whose value I want to send to a XMLHttpRequest. Now I want the user to just type the value, without pressing a button. But If i just send the request int he keyboard events, it will fire every time a key is pressed.

So basically I want something liek this

function KeyUpEvent()
{
  if (user is still typing)
    return;
  else 
    //do processing
}

It would be great if the solution could come from plain javascript or mootools. I dont want to use any other library.

+8  A: 

Basically, you want to start a timer on KeyUp, and when KeyUp starts again, reset the timer. When the user stops typing, the timer runs out, and your request can go at that point.

Example:

var timout_id;

function keyup_handler(event) {
  if (timout_id) {
    clearTimeout(timout_id);
  }

  timout_id = setTimeout(function(){
    alert('sending data: \n' + event.target.value)
  }, 800);
}

Just attach the function to the input using your preferred method, and replace the alert with your preferred action.

Of course there are many ways you could generalize this approach and make it more reusable, etc, but I think this illustrates the basic idea.

Avi Flax
+5  A: 

The way this is usually done is by restarting a timer on the keyup event. Something like this:

var keyupTimer;
function keyUpEvent(){
   clearTimeout(keyupTimer);
   keyupTimer = setTimeout(sendInput,1000); // will activate when the user has stopped typing for 1 second
} 

function sendInput(){
    alert("Do AJAX request");
}
cmptrgeekken
+2  A: 

You never know when a user is really "finished" typing. The user might take a sneeze break, or a stretch break, or a coffee break, and then continue typing.

However, if you're implementing something like an autocomplete mechanism, you can set a timer (cf. window.setTimeout(...)) to see if the user hasn't typed anything in a certain amount of time. If you get another key-up event while the timer is running, you can start the timer over.

Will
A: 

Use onBlur and maybe an onKeyDown to check for the user pressing the return/enter key.

nicerobot
Seriously!? Down-voting this when it's the only real means to know when a user is done typing?! That is, they've left the field or pressed a key indicating they want to submit. Otherwise, there's no way to know. Not a timer because they may have simply been distracted.
nicerobot
+5  A: 

I always use this simple function to handle a timer, that will fire a callback function, after the user has stopped typing for a specified amount of time:

var typewatch = (function(){
  var timer = 0;
  return function(callback, ms){
    clearTimeout (timer);
    timer = setTimeout(callback, ms);
  }  
})();

Usage (example with MooTools):

$('textInput').addEvent('keyup', function(e){
  typewatch(function () {
    // executed only 500 ms after the last keyup event
    // make Ajax request
  }, 500);
});

The main difference between this solution and solutions from other answers is that all the timer logic is handled by the typewatch function itself, the event handler doesn't need to know anything about the timer, it just invokes the function. Also, there are no global variables to take care (the timer id is not stored on a global variable).

CMS
+1  A: 
var keyTimer;
function onKeyUp(){
clearTimeout(keyTimer);
setTimeout(stoppedTyping,1500);
}
function stoppedTyping(){
// Profit! $$$
}

EDIT: Damn ninjas

M28
A: 

I wrote a custom jQuery event because I use this logic a lot:

jQuery.event.special.stoppedtyping = {
  setup: function(data, namespaces) {
    jQuery(this).bind('keyup', jQuery.event.special.stoppedtyping.keyuphandler);
  },
  teardown: function(namespaces) {
    jQuery(this).bind('keyup', jQuery.event.special.stoppedtyping.keyuphandler);
  },
  keyuphandler: function(e) {
    var interval = 1000;
    var el = this;

    if (jQuery.data(this, 'checklastkeypress') != null) {
      clearTimeout(jQuery.data(this, 'checklastkeypress'));
    }

    var id = setTimeout(function() {
      jQuery(el).trigger('stoppedtyping');
    }, interval);
    jQuery.data(this, 'checklastkeypress', id);
  }
};

You can use it like this:

$('input.title').bind('stoppedtyping', function() {
  // run some ajax save operation
});

For some reason I could never get it to work with .live( ... ). I'm not sure why...

Venkat D.