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.
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.
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.
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 );
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>
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)
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));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With