Throttling a jQuery .load() function for autocomplete - javascript

I use the following function to get autocomplete suggestions as a user types from a PHP file using jQuery .load().
How should I throttle the number of autocomplete requests being made with this function if a user is typing really fast? I'm new to this sort of thing.
<script>
function getSuggestions(){
var query = document.getElementsByName("q")[0].value;
$(document).ready(function(){
$("#suggestions").load("https://example.com/autosuggest.php", {
q: query
});
});
}
$(document).ready(function(){
let debounce;
$('.searchBox').on('keydown', function(e){
// get keycode of current keypress event
var code = (e.keyCode || e.which);
// do nothing if it's an arrow key
if(code == 37 || code == 38 || code == 39 || code == 40 || code == 13) {
return;
}
// do normal behaviour for any other key
debounce = setTimeout(() => {
getSuggestions();
}, 350);
});
$(".searchBox").click(function(){
getSuggestions();
});
});
</script>
<input class="searchBox" type="text" name="q" placeholder="" value="" onkeydown="getSuggestions()">
<div id="suggestions">
</div>

The general concept is called "debounce" - and basically you just have to set a timeout and wait to make the request for say, 500 milliseconds. Every time you receive input, you clear the timeout. Then, once they've finally stopped typing for a bit, the timeout will get triggered. Something like this (where I'm just logging the input, but you can see that it only triggers when you stop typing):
$(function() {
let debounce;
$('.searchBox').on('input', function() {
clearTimeout(debounce);
debounce = setTimeout(() => {
const value = $(this).val();
console.log({value});
/* $("#suggestions").load("https://example.com/autocomplete.php", {
q: value
}); */
}, 500);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input class="searchBox" type="text" name="q" placeholder="" value="">
<div id="suggestions">
</div>

Related

How to detect `input` value changes as user typing in?

What I want to do is that, there is an input box, when user types in any thing, the code should fire a request to the server and get back some data to users.
This is just a typeahead suggestion functionality, but still not exactly the same.
What I currently have is following code
$("input").on("input", function(ev) {
alert(`${ev.type} event detected`)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" placeholder="text">
And the code works as expected, that is saying whenever the input box value changes, the event is captured.
My question is, how to make the code wait a few seconds or milli-seconds before handling the input change events? Say fire the code 1000ms later when the input stops changing.
Since now, the code will fire per every single letter I typed in, that would results into a lots of events, which I don't want.
You can set a timer when a key is pressed and if another key is pressed and the timer is still running (timer var is not null) cancel it before setting the timer again.
var timer;
$("input").on("input", function(ev) {
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(function(){
console.log(`${ev.type} event detected`);
timer = null;
}, 1000);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" placeholder="text">
Here is a sample code to execute 1 seconds after done typing.
Basically what it does. it's simply setting a setTimeout if a key is pressed then clearingTimeout if another key is pressed before 1000ms. If not, setTimeout will execute.
var typingTimer;
var doneTypingInterval = 1000;
$("input[type='text']").on('input', function(e) {
clearTimeout(typingTimer);
typingTimer = setTimeout(doneTyping, doneTypingInterval);
});
function doneTyping() {
alert("Hey!");
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" placeholder="text">
All you need to do, is to set a timeout and a flag.
with each event, you set the flag to true, but when the timeout occurs, you only run your code once and then reset the flag for later events.
$("input").on("input", function(ev) {
$(this).data({
changed: true
});
window.setTimeout(() => {
if ($(this).data("changed") == true) {
alert(`${ev.type} event detected`);
$(this).data({
changed: false
});
}
}, 1000);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" placeholder="text" />
To detect input value changes as user typing in , You just have to check onInput event -
$('#testId').on("input", function (e) {
var valInput = $('#testId').val();
$('#inputVal').html(valInput);
$('#inputChar').html(valInput.length);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" id="testId" />
<br />
<br />
<div>You typed : <strong><span id="inputVal"></span></strong> </div>
<br />
<div>No. of character : <strong><span id="inputChar">0</span></strong> </div>

Start / Stop keypress event jquery

I have a problem. I want to stop keypress event when space is pressed, then I want to do something and finally I need to "restart" this function. It is possibile? How can I do this?
Thank you in advance
$(document).keypress(function(e) {
if(e.keyCode == 32)
// stop keypress function
// do something
// restart keypress function
}
I believe you have two choices.
Disable the handler:
$(document).on('keypress', function keypressHandler(e) {
//disable handler
$(document).off('keypress');
//do stuff
//enable keypress handler
$(document).on('keypress', keypressHandler);
});
Use a flag:
var keyHandlerActive = true;
$(document).on('keypress', function(e) {
if (!keyHandlerActive) { return; }
keyHandlerActive = false;
//do stuff
keyHandlerActive = true;
});
Try one of these functions:
e.stopPropagation();
OR
e.preventDefault();
Full code:
$(document).keypress(function(e) {
if (e.keyCode == 32) {
e.preventDefault(); // e.stopPropagation();
}
})
Your turn off condition is space, but turning back on condition is not mentioned.. so I am using a timer below.. change it as you like
To try the demo,
Type any key except space to see it get logged
Press space to turn off for 10 seconds (or change code to make it until a process complete)
function turns On after 10 seconds
The function simply turns off (logical off as bind/rebind might become a pain if overused) for 10 seconds when space is pressed.
var logicalOff = false;
$(document).keypress(function(e) {
if (logicalOff) { return true; } //well we just ignore and return until turned On
$('div').text(e.which);
if(e.which == 32) {
logicalOff = true; // stop keypress function
setTimeout(function () { // restart keypress function
logicalOff = false;
$('div').text("turned on now");
}, 10000);
$('div').text("turned off for 10 seconds");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>
Well, you can play with it like this as I have added two buttons for both situations and by default the SPACE will be disabled. Check it out please:
HTML
<input id="myinput" type="text">
<input id="space_flag" type="hidden" value="0">
<br/>
<input id="enable_space" type="button" value="Enable Space">
<br/>
<input id="disable_space" type="button" value="Disable Space">
JQuery
$(function(){
$("#myinput").keypress(function(event){
if(event.keyCode == 32 && $("#space_flag").val()==0){
return false;
}
});
$("#enable_space").click(function(event){
$("#space_flag").val(1);
});
$("#disable_space").click(function(event){
$("#space_flag").val(0);
});
});
Working example http://jsfiddle.net/1pn4cLak/

ajax, javascript - start function with two events

I have one function and I need to start in on click or on pressing Enter key.
So I'd need something like:
<BUTTON onclick="searchProduct()" or onkeypress="searchProduct()">Hledat</BUTTON>
But only on pressing Enter. Not on any key.
Is this possible for Ajax or plain javascript?
OK, didn't expect that it is so complicated, so I give you whole of my code, because your answers are not working for my whole code...
<!DOCTYPE html>
<HTML>
<HEAD>
<META charset="UTF-8" />
<TITLE>Searchin engine</TITLE>
</HEAD>
<BODY>
<SCRIPT src="js_search.js"></SCRIPT>
<FORM>
<INPUT type="text" id="word" size="40" />
</FORM>
<BUTTON onclick="searchProduct(document.getElementById('word').value)">Hledat</BUTTON>
<P id="display"></P>
</BODY>
</HTML>
Just add event listeners in your javascript (above your searchProduct() function, for instance)
document.getElementById('button').addEventListener('click', function(){
searchProduct(document.getElementById('word').value);
})
document.getElementById('button').addEventListener('keydown', function(e){
if(e.keyCode == 13) searchProduct(document.getElementById('word').value); // the keyCode 13 is equivalent to the enter key
})
function searchProduct(val) {
alert(val);
}
<button id="button">Hledat</button>
<input id="word" value="foo"/>
Hope this helps!
Ideally, you should have individual events on element and enter, you can either call specific function or you can trigger element's click.
If you wish enter and button click work same, I would suggest to trigger click event. This will make sure all UI states are updated and all processing are done. Reason for this is, we can add multiple handlers to a button for different processing and calling functions might not call other code.
function keyPress(e) {
if (e.keyCode == 13) {
document.getElementById("btn").click();
}
}
function notify() {
console.log("Processing...")
}
<input type="text" id="txt" onkeyup="keyPress(event)">
<button id="btn" onclick="notify(event)">Notify</button>
You can do:
<BUTTON onclick="searchProduct()" onkeypress="searchProductKeyPress(event)">Hledat</BUTTON>
function searchProductKeyPress(event) {
if (event.which == 13 || event.keyCode == 13) {
searchProduct();
return false;
}
return true;
}
In the function you can pass the event like this:
<BUTTON onclick="searchProduct(event)" onkeypress="searchProduct(event)">Hledat</BUTTON>
Now in the function:
searchProduct(e){
if(e.type === 'keypress' && e.keyCode !== 13){
return;
}
// put the code for search here.
}
set id="btn_search_product" to your button
var btn_search_product = document.getElementById("btn_search_product");
btn_search_product.addEventListener("keydown", function (e) {
if (e.keyCode === 13) {
searchProduct(e);
}
});
I actually use evento library https://github.com/petermichaux/evento
with it it would be:
evento.add(btn_search_product, "keydown", function (e) {
if (e.keyCode === 13) {
searchProduct(e);
}
});

suggestion list catching user input delay

I wrote below code to retrieve suggestion using ajax when the user is typing. The problem is the call may be too many so I used setTimeout. Is my flow done correctly?
$('.text').on('keydown', function(e) {
if ($(this).val().length >= 3) {
var suggestionURL = "example.com?q"
+ $(this).val();
setTimeout(function(){
show_suggestion();
}, 1000);
function show_suggestion(){
// $.ajax..
}
}
});
You can use setTimeout() and clearTimeout() for this. This will ensure that the function is only called it the user has typed more than 3 characters and has stopped typing for at least half a second. Adjust the time as needed:
$(function() {
var timeOut = 0;
$(".text")
.keyup(function() {
// check input has at least 4 chars
if ($(this).val().length >= 3) {
// cancel looking, the user typed another character
clearTimeout(timeOut);
// set a timeout
// if user doesn't type another key
// within half a second the function is called
timeOut = setTimeout(function() {
show_suggestion();
}, 500); // change time as needed
}
});
});
function show_suggestion(){
alert('user stopped typing, call the ajax');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" class="text"/><br><br>
<input type="text" class="text"/><br><br>
<input type="text" class="text"/><br><br>
<input type="text" class="text"/><br><br>

RegExp for current character JavaScript

I'm trying to validate a character to make sure it's a letter (not a number, symbol, etc.) BEFORE it's allowed to be entered into the form field. How can I do that with JavaScript?
Here is something I tried:
<script type="text/javascript">
function checkTest() {
var letterValue = document.forms[0].test.value;
var letterCheck = /[a-z]/i;
var letterTest = letterValue.test(letterCheck);
}
</script>
<html>
<body>
<form>
<input type="text" name="test" onkeypress="checkTest();"/>
</form>
</body>
</html>
This code will check the string of the value. I've tried using var letterLeng= letterValue.length and then using var letterChar = letterValue.charAt(letterLeng) or even var letterChar = letterValue.charAt(letterLeng - 1) and all to no avail. Any advice would be much appreciated.
Ask the event for the key that was pressed then test it:
function checkTest(event) {
event = event || window.event;
if (!/[A-Za-z]/.test(String.fromCharCode(event.keyCode || event.which))) {
if (event.preventDefault)
event.preventDefault();
else
event.returnValue = false;
}
}
<input type="text" name="test" onkeypress="checkTest(event);"/>
I like Alex K's answer, but I could not get the 'onkeypress' handler to work so I tried something using Jquery. It doesn't keep the bad letters from appearing briefly, but it does keep them from being entered.
It uses the 'keyup' event, which actually makes checking for the key code much easier in this instance since you want to limit it to [a-zA-Z]
$("#myinput").on("keyup", function (e) {
// Ignore the shift key.
if (e.keyCode === 16) {
return true;
}
if ((e.keyCode < 65 || e.keyCode > 90)) {
var str = $("#myinput").val();
$("#myinput").val(str.slice(0, str.length - 1));
}
});
The working fiddle is here: http://jsfiddle.net/yaa9snce/
What you are looking for is the onkeypress event.
<input type="text" onkeypress="myFunction()">
<script>
function myFunction() {
alert("You pressed a key inside the input field");
}
</script>

Categories