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

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

Posted by: admin November 2, 2017 Leave a comment

Questions:

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?

Answers:

I use this function for the same purpose, executing a function after the user has stopped typing for a specified amount of time:

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

Usage:

$('input').keyup(function() {
    delay(function(){
      alert('Time elapsed!');
    }, 1000 );
});

For something more sophisticated, give a look to the jQuery Typewatch plugin.

Questions:
Answers:

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);  
}   

Questions:
Answers:

You could also look at underscore.js, which provides utility methods like debounce:

var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);

Questions:
Answers:

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);});

Questions:
Answers:

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

Questions:
Answers:

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{  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

Questions:
Answers:

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.

Questions:
Answers:

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);
});

Questions:
Answers:

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/

Questions:
Answers:

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 );

Questions:
Answers:

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);
}

Questions:
Answers:

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.

Questions:
Answers:

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.

Questions:
Answers:

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 );


})

Questions:
Answers:

Super simple approach, designed to run a function after a user has finished typing in a text field…

<script type="text/javascript">
$(document).ready(function(e) {
    var timeout;
    var delay = 2000;   // 2 seconds

    $('.text-input').keyup(function(e) {
        console.log("User started typing!");
        if(timeout) {
            clearTimeout(timeout);
        }
        timeout = setTimeout(function() {
            myFunction();
        }, delay);
    });

    function myFunction() {
        console.log("Executing function for user!");
    }
});
</script>

<textarea name="text-input" class="text-input"></textarea>

Questions:
Answers:

Use the bindWithDelay jQuery plugin:

element.bindWithDelay(eventType, [ eventData ], handler(eventObject), timeout, throttle)

Questions:
Answers:
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
};

Questions:
Answers:

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);
});

Questions:
Answers:

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');
});

Questions:
Answers:

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.

Questions:
Answers:

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 */ });
});

Questions:
Answers:

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);
                });