Run javascript function when user finishes typing instead of on key up?

Run javascript function when user finishes typing instead of on key up?

I want to trigger an ajax request when the user has finished typing in a text box. I don’t want it to run the function on every time the user types a letter because that would result in A LOT of ajax requests, however I don’t want them to have to hit the enter button either.
Is there a way so I can detect when the user has finished typing and then do the ajax request?
Using jQuery here!
Dave

Solutions/Answers:

Solution 1:

So, I’m going to guess finish typing means you just stop for a while, say 5 seconds. So with that in mind, lets start a timer when the user releases a key and clear it when they press one. I decided the input in question will be #myInput.

Making a few assumptions…

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 5000;  //time in ms, 5 second for example
var $input = $('#myInput');

//on keyup, start the countdown
$input.on('keyup', function () {
  clearTimeout(typingTimer);
  typingTimer = setTimeout(doneTyping, doneTypingInterval);
});

//on keydown, clear the countdown 
$input.on('keydown', function () {
  clearTimeout(typingTimer);
});

//user is "finished typing," do something
function doneTyping () {
  //do something
}

Solution 2:

The chosen answer above does not work.

Because typingTimer is occassionaly set multiple times (keyup pressed twice before keydown is triggered for fast typers etc.) then it doesn’t clear properly.

The solution below solves this problem and will call X seconds after finished as the OP requested. It also no longer requires the redundant keydown function. I have also added a check so that your function call won’t happen if your input is empty.

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 5000;  //time in ms (5 seconds)

//on keyup, start the countdown
$('#myInput').keyup(function(){
    clearTimeout(typingTimer);
    if ($('#myInput').val()) {
        typingTimer = setTimeout(doneTyping, doneTypingInterval);
    }
});

//user is "finished typing," do something
function doneTyping () {
    //do something
}

And the same code in vanilla JavaScript solution:

//setup before functions
let typingTimer;                //timer identifier
let doneTypingInterval = 5000;  //time in ms (5 seconds)
let myInput = document.getElementById('myInput');

//on keyup, start the countdown
myInput.addEventListener('keyup', () => {
    clearTimeout(typingTimer);
    if (myInput.value) {
        typingTimer = setTimeout(doneTyping, doneTypingInterval);
    }
});

//user is "finished typing," do something
function doneTyping () {
    //do something
}

This solution does use ES6 but it’s not necessary here. Just replace let with var and the arrow function with a regular function.

Solution 3:

It’s just one line with underscore.js debounce function:

$('#my-input-box').keyup(_.debounce(doSomething , 500));

This basically says doSomething 500 milliseconds after I stop typing.

For more info: http://underscorejs.org/#debounce

Solution 4:

Yes, you can set a timeout of say 2 seconds on each and every key up event which will fire an ajax request. You can also store the XHR method and abort it on subsequent key press events so that you save bandwith even more. Here’s something I’ve written for an autocomplete script of mine.

var timer;
var x;

$(".some-input").keyup(function () {
    if (x) { x.abort() } // If there is an existing XHR, abort it.
    clearTimeout(timer); // Clear the timer so we don't end up with dupes.
    timer = setTimeout(function() { // assign timer a new timeout 
        x = $.getJSON(...); // run ajax request and store in x variable (so we can cancel)
    }, 2000); // 2000ms delay, tweak for faster/slower
});

Hope this helps,

Marko

Solution 5:

var timer;
var timeout = 1000;

$('#in').keyup(function(){
    clearTimeout(timer);
    if ($('#in').val) {
        timer = setTimeout(function(){
            //do stuff here e.g ajax call etc....
             var v = $("#in").val();
             $("#out").html(v);
        }, timeout);
    }
});

full example here: http://jsfiddle.net/ZYXp4/8/

Solution 6:

I like Surreal Dream’s answer but I found that my “doneTyping” function would fire for every keypress, i.e. if you type “Hello” really quickly; instead of firing just once when you stop typing, the function would fire 5 times.

The problem was that the javascript setTimeout function doesn’t appear to overwrite or kill the any old timeouts that have been set, but if you do it yourself it works! So I just added a clearTimeout call just before the setTimeout if the typingTimer is set. See below:

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 5000;  //time in ms, 5 second for example

//on keyup, start the countdown
$('#myInput').on("keyup", function(){
    if (typingTimer) clearTimeout(typingTimer);                 // Clear if already set     
    typingTimer = setTimeout(doneTyping, doneTypingInterval);
});

//on keydown, clear the countdown 
$('#myInput').on("keydown", function(){
    clearTimeout(typingTimer);
});

//user is "finished typing," do something
function doneTyping () {
    //do something
}

N.B. I would have liked to have just added this as a comment to Surreal Dream’s answer but I’m a new user and don’t have enough reputation. Sorry!