I have a jQuery Ajax request, that I want to call with text input, and so I nested it inside keyup(function(). This works fine.
$("#text_box").keyup(function() {
//AJAX REQUEST
});
But this behaves buggy sometimes. When I input some text very fast, I am getting results for input word with some last letters of the original input word omitted (may be some fault with browser). I want the ajax request to be sent when there is no input activity for a second, I mean, if I input text very fast and rest for a second (means I made the input). How can I do this?
It sounds as if you get results from a previous ajax call. Use a timer with setTimeout and clearTimeout.
var timer = null;
$("#text_box").keyup(function() {
if(timer) {
clearTimeout(timer);
}
timer = setTimeout(someFunction, someDelay);
});
Where someFunction is a function which does your ajax call and someDelay is the delay you want to wait before doing the call, after the user has typed, in ms.
As you are already using jQuery you could use the debounce plugin from Ben Aleman.
Example from the page
// Bind the not-at-all debounced handler to the keyup event.
$('input.text').keyup( text_1 );
// Bind the debounced handler to the keyup event.
$('input.text').keyup( $.debounce( 250, text_2 ) ); // This is the line you want!
omg. for somebody who will search in 2014...
function sendAjax() {
setTimeout(
function() {
$.ajax({
url: "url.php",
type: "POST",
data: data,
success: function(data) {
$("#result").html(data);
}
});
}, 2000);
}
<input onkeyup="function()">
Related
I have just started learning javascript and what I am doing is making request to my Django API. So I found I can use Ajax requests to do so.
SO I made a search bar that would call the API after waiting 1 sec on the keyup action.
input.addEventListener('keyup', function (e) {
clearTimeout(timeout);
timout = setTimeout(function () {
runScript(input.value);
}, 1000);
});
The runscript function is the one making Ajax requests
function runScript(input) {
var jqXHR = $.ajax({
url: "http://localhost:8090/api/movie/?name=" + input,
datatype: 'json',
success: callbackFunc
});
return jqXHR.responseText;
}
and the callbackFunc is what I would like to do with the response
function callbackFunc(response) {
// do something
}
The problem is that ajax is making multiple requests to the API. How do I stop Ajax from making multiple requests ?
Related: Prevent ajax call from firing twice, Ajax, prevent multiple request on click
You can use the stopImmediatePropagation method which is meant for cases like this. https://developer.mozilla.org/en-US/docs/Web/API/Event/stopImmediatePropagation.
If several listeners are attached to the same element for the same event type, they are called in the order in which they were added. If stopImmediatePropagation() is invoked during one such call, no remaining listeners will be called.
You only need to add the method call on you timeout function like this
timeout = setTimeout(function () {
e.stopImmediatePropagation()
runScript(input.value);
}, 1000);
Full fiddle here https://jsfiddle.net/zgranda/fujw6tvp/9/
I am sending an ajax request when the user hit the search button in the following manner:
$('#search').on('click',function(){
$('#searchResponse').hide();
$('#searchResponse').html('<img src="assets/img/loading.gif">');
$('#searchResponse').show();
$.ajax({type:'POST',url:'assets/php/handler.php',data:$('#form').serialize(),success:function(response){
$('#searchResponse').html(response);
}});
return false;
});
Everything is working fine but I want to have something like an automatic update after the above happens. This means I have to set up something like a timeout after the request is completed so the ajax is fired again. I've tried the following but with no success unfortunately:
$('#search').on('click',function(){
$('#searchResponse').hide();
$('#searchResponse').html('<img src="assets/img/loading.gif">');
$('#searchResponse').show();
$.ajax({type:'POST',url:'assets/php/handler.php',data:$('#form').serialize(),success:function(response){
$('#searchResponse').html(response);
},complete:function(){
setTimeout(this, 5000);
}});
return false;
});
I guess that the selector isn't right but what alternative should I use to suits my needs? Any help of guidance is more than welcomed.
You are not providing a suitable method for the setTimeout call. this is the ajax context. As you want to call the same upload a second time after 5 seconds, try like this:
$('#search').on('click', function () {
$('#searchResponse').hide();
$('#searchResponse').html('<img src="assets/img/loading.gif">');
$('#searchResponse').show();
var doAjax = function () {
// return the ajax promise
return $.ajax({
type: 'POST',
url: 'assets/php/handler.php',
data: $('#form').serialize(),
success: function (response) {
$('#searchResponse').html(response);
}
});
});
// Call once then again on success
doAjax().done(function(){setTimeout(doAjax, 5000);});
return false;
});
Notes: jQuery.Ajax returns a deferred's promise that you can use to chain together functionality. Although promises are initially more confusing than say callbacks they are far more powerful and worth learning. You will change the way you write your code once you try them :)
Side-issue:
As #Peter Herdenborg points out, these three lines hiding and showing the response are not all required. The reason is that they all happen on the same render cycle, so you will not see a visual flash.
e.g. this:
$('#searchResponse').html('<img src="assets/img/loading.gif">');
will do the same as this:
$('#searchResponse').hide();
$('#searchResponse').html('<img src="assets/img/loading.gif">');
$('#searchResponse').show();
You need to extract out the ajax bits to a function which either calls itself with a delay or that is simply called using setInterval(). I also don't see a point in hiding #searchResponse before changing its contents, so I've removed that and the related .show().
$('#search').on('click',function(){
$('#searchResponse').html('<img src="assets/img/loading.gif">');
loadResults();
setInterval(loadResults, 5000);
return false;
});
function loadResults(){
$.ajax({
type:'POST',
url:'assets/php/handler.php',
data: $('#form').serialize(),
success: function(response){
$('#searchResponse').html(response);
}
});
}
jQuery 2.0.3
I want to fire off an AJAX call when data changes in an edit input control. I realise I can do this via the onChange event. However if the user enters: 123 I don't want to fire the AJAX 3 times.
Instead I want to wait for a "setting period" and then fire off the call. The setting period gets reset each time the control changes. So the idea being as I type 123 quickly, some time passes (settling) and I make the AJAX call.
Does anyone have any suggestions on how to implement this with jQuery? Are there any constructs I can use in jQuery to do this?
You'll need to throttle the event with a timeout
$('input').on('keyup', function() {
var self = this;
clearTimeout( $(this).data('timer') );
$(this).data('timer',
setTimeout(function() {
$.ajax({
url : 'someurl.php',
data : self.value
});
}, 500)
)
})
Easy way is with setTimeout / clearTimeout on the change event:
var timeout = null;
$('input').bind('keyup blur', function() {
if (timeout !== null) clearTimeout(timeout);
timeout = setTimeout(function() {
// Make your ajax request here
}, 300);
});
Change the 300 to number of milliseconds you want to have to wait before the ajax request is made.
When the city input field is blurred I get somnething via an ajax request and set that as the value of a hidden field in the same form that the city field resides in.
$('input#city').on('blur', function() {
$.ajax({
url: 'get/something?param=val',
success: function(response) {
$('input:hidden[name="something"]').val(response);
}
});
});
If the user submits the form immediately after blurring off the city field sometimes due to latency the hidden field is not populated because the SQL on the other end is taking too long.
The form that both these fields are in is also submitted via ajax:
$('form#find-users').on('submit', function() {
if(NO_AJAX_CURRENTLY_RUNNING_ON_PAGE) {
// do stuff
}
});
How to detect if no ajax is running on the page? This will ensure that the city ajax was completed and the hidden field populated before the form is processed.
EDIT
Actually it won't, it will only prevent the form from being submitted. But if I can detect that then I can use a setInterval and keep trying to run that code until it runs because ajax is complete. Ideally there will be something in jQuery that waits until other ajax is complete and then submits.
Use jQuery's Ajax Events. As long as all of your Ajax calls are generated using jQuery, you have a way of knowing if any Ajax calls are outstanding.
$(document).ready(function() {
var ajaxBusy = false;
$(document).ajaxStart( function() {
ajaxBusy = true;
}).ajaxStop( function() {
ajaxBusy = false;
});
});
Edit:
So that answers your direct question about "How do I know if there is any Ajax call running."
Alternatively, you could disable the form's submit buttons when run your blur handler, and then re-enable it when you're done.
$('input#city').on('blur', function() {
var submit = $(this).closest('form').find(':submit:enabled');
submit.prop('disabled', true);
$.ajax('get/something?param=val').done(function(response) {
$('input:hidden[name="something"]').val(response);
}).always(function() {
submit.prop('disabled', false);
});
});
Edit 2:
So now we're at the point where we would like to delay the form submission until all current Ajax calls have completed. We let people click on the submit button, but if there are pending Ajax calls we don't do anything right away.
We can use a Deferred object to help us with this.
$(document).ready(function() {
var ajaxDefer = $.Deferred().resolve();
$(document).ajaxStart( function() {
ajaxDefer = $.Deferred();
}).ajaxStop( function() {
ajaxDefer.resolve();
});
$('form#find-users').on('submit', function() {
ajaxDefer.always(function() {
// Code here will always be executed as soon as there are no
// Ajax calls running.
// this points to the deferred object (ajaxDefer), so use the closure
// to carry over any variables you need.
});
});
});
When we're just starting out, we set up our ajaxDefer object in a resolved state. That means any functions attached using .always() will execute immediately.
When the first Ajax call starts, we replace the old ajaxDefer object with a new one that has not been resolved. Any new functions attached using ajaxDefer.always() will be deferred until later.
When the last Ajax call completes, we call ajaxDefer.resolve(), which causes any unexecuted deferred functions to execute. Now we're back to our initial state, where any newly-attached functions will execute immediately.
When somebody tries to submit the form, create an anonymous function that does the work and attach it to ajaxDefer. It will get executed when appropriate, depending on if there are any outstanding Ajax requests or not. Be mindful of your closures.
Use this to check if AJAX calls are currently in-progress using JQuery:
if ($.active == 0) {
...
}
you can put a variable in the global namespace, perhaps named ajaxLock and toggle it on when AJAX starts and off when the response comes. Then check it before allowing submit.
something like
var ajaxLock = 1;
$('input#city').on('blur', function() {
$.ajax({
url: 'get/something?param=val',
success: function(response) {
$('input:hidden[name="something"]').val(response);
ajaxLock = 0;
}
});
});
Use a lock variable like you suggested:
$('input#city').on('blur', function() {
window.AJAX_CURRENTLY_RUNNING_ON_PAGE = true;
$.ajax({
url: 'get/something?param=val',
success: function(response) {
$('input:hidden[name="something"]').val(response);
},
complete: function() { window.AJAX_CURRENTLY_RUNNING_ON_PAGE = false; }
});
});
$('form#find-users').on('submit', function() {
if(window.AJAX_CURRENTLY_RUNNING_ON_PAGE) {
return;
}
//dostuff
});
What i could have done on this circumstances is to use plugin like block ui or disable the form submit button,the reason is you need to be interactive in your design,you may well able to lock the form submission,but its better to give a message or have a modal gray out
Is there any way to time how long a jquery ajax request has been going on? sometimes searches take too long and it would be nice to add a jquery abort() button if the search takes over, say, 5 seconds. Any way I can do this!
On the other end of the ajax request is a php file that makes a postgresql request.
Much thanks for any ideas!
Take a look at the timeout option (http://api.jquery.com/jQuery.ajax/). You can set it on a particular call, or globally with $.ajaxSetup().
To have the abort button appear after 5 seconds, add a setTimeout function after your call to send. Once the AJAX command is complete, you can add code to clear the timeout and remove the abort button if it exists.
var timeOutID = 0;
$.ajax({
url: 'ajax/test.html',
success: function(data) {
clearTimeOut(timeOutID);
// Remove the abort button if it exists.
}
});
timeOutID = setTimeout(function() {
// Add the abort button here.
}, 5000);
This way the abort button will never appear if AJAX returns quick enough.
Usually, I'll set a timeout once the request is sent that will trigger after 10 seconds or so and then fallback on something else to make sure it still happens (for example, form submission).
So set a variable to false, var failed = false; and do the request
At the same time that the request starts, set a timeout:
setTimeout(function() {
failed = true;
$("#form").submit();
return false;
}, 10000);
In the return function of the ajax call, check to see if the failed variable has been set to true, and if it has, don't actually do whatever it was originally trying, otherwise it could mess something up, or confuse the user if something else is happening (since these things usually happen on slower internet connections, if the next step appears while a new page is loading, they might try to interact and then the page will change).
$.post("ajaxcall.php", {'etc': "etc"},
function(returned) {
if (failed != true) {
//do whatever with returned variable
}
});
var timer = 0,
XHR = $.ajax({
url: 'ajax/mypage.html',
beforeSend: function() {
timer=setTimeout(showAbort, 5000);
}
});
function showAbort() {
$('<input type="button" value="Abort" id="abort_button"/>').appendTo('#some_parent');
$('#abort_button').on('click', function() {
XHR.abort(); //abort the Ajax call
});
}
XHR.always(function() { //fires on both fail and done
clearTimeout(timer);
if ($('#abort_button').length) {
$('#abort_button').remove(); //remove button if exists
}
});