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>
Related
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>
I have an
<input type="number" class="post-purchase-amount"/>.
I am calling an
ajax call when the value get changed. It is working (with the following code) when the cursor is in the
text box itself and doing any changes. But it not working when i click the spinner (up/down button) of the input type.
parentPanel.on("change", ".post-purchase-amount", null, function (event) {
updateAmount($(this));
});
My problem is that i could use the "input" event here but that can call the ajax
every time when in change the value like if i want to send value 65
then it calls twice when typing each number. I need to call ajax only when the value has been changed not every key
stroke.
Sorry for my English. Thanks in advance
How about you create a function to throttle the input and trigger it on keypress instead. Something like this:
function throttle(func, interval) {
var last = 0;
return function() {
var now = Date.now();
if (last + interval < now) {
last = now;
return func.apply(this, arguments);
}
};
}
parentPanel.on("keypress", ".post-purchase-amount", null, throttle(function(event) {
updateAmount($(this));
}, 800));
Your problem is that you are watching for a change and anytime you make a change this is going to fire. What you could do instead is use focusout to watch when you "exit" the number input. What the below function does is it checks to see if the previous value is equal to the new value when you exit focus on the input. If the current value is not the same then it has been updated.
var prevVal = $('.numOfPeople').val();
$('.numOfPeople').on('focusout', null, function(e) {
var curVal = $('.numOfPeople').val();
if(prevVal !== curVal) {
//Value is different so do your updates here.
preVal = curVal;
$('#changed').show();
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input class="numOfPeople" type="number" name="quantity" min="1" max="5">
<p id="changed" style="display: none;">Value has changed</p>
I have some jQuery with a lot of different click events. Some of my users are habitual double clickers, which because I have no double click events bound, fires the single click event twice; this can be a pain - for example if one click opens something, and another closes it, double clicking is a zero-sum game.
Is there any way to bind all double click events to their single click equivalent without have the code them individually?
I don't think mapping dblclick to click would help; I'd think it would make things worse, if anything.
You've said you hook up your events using delegation. You could give yourself a function that debounces calls to your event handler:
// Very simple debounce, accepts first event and disregards
// subsequent ones for a period of time
function debouncedHandler(handler, delay) {
delay = delay || 300; // milliseconds, I'm told Windows uses 500 but that seems awfully long
var last;
return function() {
var now = Date.now();
if (last && last + delay > now) {
return false;
}
last = now;
return handler.apply(this, arguments);
};
}
$(document).on("click", "input[type=button]", debouncedHandler(function() {
$(".container").toggleClass("toggle-open toggle-closed");
}));
.toggle-open .closed {
display: none;
}
.toggle-closed .open {
display: none;
}
<input type="button" value="Open/Close">
<div class="container toggle-open">
<span class="open">OPEN</span>
<span class="closed">closed</span>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
HTML
<button class="btn">
click me
</button>
JQUERY
$(document).ready(function(){
var clickDisabled = false;
$('.btn').click(function(){
if (clickDisabled)
return;
// do your real click processing here
console.log('hi');
clickDisabled = true;
setTimeout(function(){clickDisabled = false;}, 5000);
});
});
kindly check https://jsfiddle.net/05tvvaeq/
preventing click handler for 5secs (you can set the time as per your need)
check console to see the result
This is what I would do it:
<input type="hidden" id='counter' value='0'>
<input type="button" value="Save" onclick="save()">
function save(){
var counter = parseInt(document.getElementById("counter").value);
counter = counter+1;
if(counter == 1){
console.log('Saving...')
}
document.getElementById("counter").value = counter;
//after 3 seconds set counter back to 0
setTimeout(function(){
document.getElementById("counter").value = 0;
}, 3000)
}
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>
If someone mouseovers a text box for a second, I want to show a div. But I don't want it to show if they just mouseover quickly as the mouse passes over the text box.
<input type="text" value="Fred" onmouseover="overit()">
<div id="dv" style="display:none">Jim</div>
var delay;
function overit()
{
delay = window.setTimeout('showme();', 1000);
}
function showme()
{
document.getElementById('dv').style.display = 'block';
}
Unless someone mouseovers the text box for a second, I don't want showme() to be called. How can I cancel showme() being called if the gap between mouseover and mouseout is not at least a second?
Fiddle at http://jsfiddle.net/S4jx4/
I don't want to use jquery
Your proposed solution almost works. Add an onmouseout listener on the input to cancel the timeout.
<input type="text" value="Fred" onmouseover="overit()" onmouseout="window.clearTimeout(delay);">
http://jsfiddle.net/TN952/
You know the function WILL be called after 1 second, so you don't really have to check if the gap is there, you just have to cancel the timeout when mouseleave happens. If it's already been called, it's been less than a second, and cancelling it doesn't affect anything.
var delay;
function overit()
{
delay = window.setTimeout('showme();', 1000);
}
function showme()
{
document.getElementById('dv').style.display = 'block';
}
function leaveit() {
window.clearTimeout(delay);
}
<input type="text" value="Fred" onmouseenter="overit()" onmouseleave="leaveit()">
<div id="dv" style="display:none">Jim</div>
http://jsfiddle.net/hXE28/
remove the inline javascript
<input type="text" value="Fred" id="txt" />
<div id="dv" style="display:none">Jim</div>
and use event listeners
var input = document.getElementById('txt'),
text = document.getElementById('dv'),
timer;
input.addEventListener('mouseenter', function() {
timer = setTimeout(showme, 1000);
}, false);
input.addEventListener('mouseleave', function() {
clearTimeout(timer);
}, false);
function showme() {
text.style.display = 'block';
}
FIDDLE