Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to trigger an onkeyup event that's delayed until a user pauses their typing?

I have a textarea where people enter some text (naturally), and I want to make it so that an AJAX request is made every now and then to get some suggestions regarding what the textarea is about (like stack overflow's Related Questions, but for a textarea, not a text input). The problem is that I can't do an AJAX request at every keypress (it'd be useless and very resource consuming), and I am not sure what would be the most efficient way to do it (every X words? every X seconds? or something else?).

What would be the best way to go about doing this?

Thank you in advance.

like image 813
Bruno De Barros Avatar asked Oct 25 '09 10:10

Bruno De Barros


People also ask

How do you delay the Keyup handler until the user stops typing?

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.

How do I delay a Keyup event?

In this article, we will see how to use keyup with a delay in jQuery. There are two ways to achieve the same: Approach 1: Using the keypress(), fadeIn(), delay() and fadeOut() methods in the jQuery library and clearTimeout() and setTimeout() methods in native JavaScript.


4 Answers

You could combine a keypress event handler with setTimeout so that you send an Ajax request a set amount of time after a keypress, cancelling and restarting the timer if another keypress occurs before the timer finishes. Assuming you have a textarea with id 'myTextArea' and an Ajax callback function called doAjaxStuff:

function addTextAreaCallback(textArea, callback, delay) {
    var timer = null;
    textArea.onkeypress = function() {
        if (timer) {
            window.clearTimeout(timer);
        }
        timer = window.setTimeout( function() {
            timer = null;
            callback();
        }, delay );
    };
    textArea = null;
}

addTextAreaCallback( document.getElementById("myTextArea"), doAjaxStuff, 1000 );
like image 143
Tim Down Avatar answered Oct 10 '22 15:10

Tim Down


What you're looking for is called debouncing. Here is a generic algorithm in native JavaScript:

function debounce(fn, duration) {
  var timer;
  return function() {
    clearTimeout(timer);
    timer = setTimeout(fn, duration)
  }
}

And here's an example of how to use it with an onkeyup event:

function debounce(fn, duration) {
  var timer;
  return function(){
    clearTimeout(timer);
    timer = setTimeout(fn, duration);
  }
}

const txt = document.querySelector('#txt')
const out = document.querySelector('#out')
const status = document.querySelector('#status')

const onReady = () => {
  txt.addEventListener('keydown', () => {
    out.classList.remove('idle')
    out.classList.add('typing')
    status.textContent = 'typing...'
  })
  
  txt.addEventListener('keyup', debounce(() => {
    out.classList.remove('typing')
    out.classList.add('idle')
    status.textContent = 'idle...'
  }, 800))
}

document.addEventListener('DOMContentLoaded', onReady)
#wrapper{
  width: 300px;
}

input{
  padding: 8px;
  font-size: 16px;
  width: 100%;
  box-sizing: border-box;
}

#out{
  margin: 10px 0;
  padding: 8px;
  width: 100%;
  box-sizing: border-box;
}

.typing{
  background: #A00;
  color: #FFF;
}

.idle{
  background: #0A0;
  color: #FFF;
}
<div id="wrapper">
  <input id="txt" placeholder="Type here" />
  <div id="out">Status: <span id="status">waiting...</span></div>
</div>
like image 35
Trevor Avatar answered Oct 10 '22 15:10

Trevor


Another alternative is to use a small jQuery plugin called bindWithDelay. It uses the same setTimeout technique that the accepted answer has, but handles the timeouts transparently so your code is a little easier to read. The source code can be seen on github.

$("#myTextArea").bindWithDelay("keypress", doAjaxStuff, 1000)
like image 39
Brian Grinstead Avatar answered Oct 10 '22 15:10

Brian Grinstead


If you are using lodash.js (or underscore.js) you can use the debounce function.

Example (jQuery used for keyup):

$('#myTextArea').keyup(_.debounce(function() {
  alert('hello');
}, 500));
like image 45
Nick Russler Avatar answered Oct 10 '22 15:10

Nick Russler