I need to check for a condition and run an AJAX call before sending other AJAX calls on my web app.
I was thinking about putting this AJAX call in a beforeSend on ajaxSetup with async: false (to prevent my initial call from running before this one has completed).
Something like this:
//I set an event that fires:
$.ajax({
type: "GET",
url: my_url,
beforeSend: function() {
//do something, like show a spinner loader gif
}
});
//Somehwere in my app I also have:
$.ajaxSetup({
beforeSend: function() {
if(x===1){
$.ajax({
type: "GET",
url: my_url/fetch_something,
async:false
});
}
}
});
Will my beforeSend on the first AJAX call overrun the one in the ajaxSetup? Is there a way to approach this better?
Better idea of my app:
I have a lot of Ajax calls through the app, each call sends a security hash on the headers to validate the user, these hashes have a time limit as well (both hash and time limit are saved in localStorage)
What I want from ajax setup (and the condition in it) is to check for the time limit - if time_limit < current_time than run an ajax call to refresh the users hash.
This isn't an exercise for 1 or 2 calls, I literally have 20+ growing Ajax calls on my app that make use of the users hash and it's very impractical to make this check in every single one of them.
UPDATED:
Have one method on an interval that sets up the 'session'/local-storage
var refreshing = false;
var intervalID;
$(document).ready(function(e){
var delay = 1234;
intervalID = window.setInterval(setupInterval, delay);
});
function setupInterval(){
refreshing = true;
$.ajax(URL).done(function(r) { //do stuff
setupStorage(r);
refreshing = false;
});
}
function setupStorage(info){
//setup whatever here
}
OLD:
Could you use some logic in your ready function to gate what you need to do?
So basically call one ajax call -> if false, just schedule your latter methods, otherwise run the setup one and on completion schedule the latter method.
Some pseudo-code:
var refresh = false;
$(document).ready(function(e){
$.ajax(URL).done( function(r) {
if(r) {
routeOne();
} else {
latter();
}
});
});
function routeOne(){
$.ajax(URL).done(function(r) { //do stuff
latter();
});
}
function latter(){
//All other ajax calls
}
I'll put some more thought into this let me finish my coffee first...
EDIT:
Based on your updated description could it be possible for you to schedule a setInterval to run the checking method/hash update on the time interval that you need, and is the time interval on your server static or variable? Facebook does this with a heartbeat, I've used this type of logic with some 'locking' functionality in a web-app. If you schedule the interval properly it should not interrupt any other ajax calls.
Try overriding $.ajax to make a "pre-call" before passing in your given query options:
var oldAjax = $.ajax;
$.ajax = function() {
var args = arguments;
oldAjax({
type: "GET",
url: "/echo/html/",
success: function(result){
// do something here to check result
// if result is good, do the request:
return oldAjax.apply($, args);
// if its bad, handle the error
}
});
}
Here's a fiddle to demonstrate: http://jsfiddle.net/NF76U/
I suggest the use of .done() ( $.Deferred object)
function AjaxCall() {
return //code of your ajax without async:false
}
function anotherAjaxCall{
return //code of you ajax call
}
AjaxCall.done(anotherAjaxCall);
Avoid using async:false it's a deprecated practice and it stucks browsers
Related
I have what might be a tricky question.
I am working on a form where it verifies a couple things on submit, using event.preventDefault(); to prevent the form from submitting if something went wrong. The issue here is that it sends multiple ajax requests at the same time, which seems to stop the php (which is processing the AJAX call) from modifying the $_SESSION variable.
I have determined this by changing the jquery ajax calls to process synchronously, allowing the $_SESSION variable to be changed.
My question is this: is there a way to allow the ajax calls to happen synchronously while allowing the $_SESSION variable to be modified during the process of those calls? I realize that the async:false for an AJAX call is deprecated, and obviously not the best solution.
Due to what each call does, it is not possible to combine the functionality of these two calls, although each call does not take long at all to process.
Example jquery code to explain how I am making these AJAX calls (some redaction and simplification, obviously):
$("#form-id").on('submit', function(event) {
$.ajax({
type: 'POST',
url: '/url/to/processing.php',
async:false, //fails without setting to false
...
});
});
...
$("#form-id").on('submit', function(event) {
$.ajax({
type: 'POST',
url: '/url/to/processing2ThatSetsSession.php',
async:false, //fails without setting to false
...
});
});
You have to concat the calls, to run one call after the other has ended.
I'll do it this way:
function ajaxPost(url, callback) {
$.ajax({
type: 'POST',
url: url
...
}).done(callback);
}
$("#form-id").on('submit', function(event) {
event.preventDefault(); // Always stop the event
// Do one ajax call and wait for the data
ajaxPost('/url/to/processing.php', function(data) {
// Do things with returned data and call the next ajax
ajaxPost('/url/to/processing.php', function(moredata) {
// Do something with moredata
// If everything is fine, re-post it but this time do not catch the event
$("#form-id").off("submit").submit();
});
});
});
You can add your own logic to show your error message in any callback and not continue with the next one.
With this I'll do an special method for multiple ajax form validation:
// This function will get an array of objects and
// do an ajax call and process the data, one after another
function multiAjax(calls, callback) {
var call = calls.shift();
if (call) {
var url = call.url;
post(url, function(data) {
var error = call.process(data);
if (error) {
callback(error);
} else {
multiAjax(calls, callback);
}
});
} else {
callback();
}
}
// This is the array of objects that multiAjax will process.
// You can add or remove elements to your likings, without modifying
// the submit event callback
var ajaxArray = [{
url: '/url/to/processing.php',
process: function(data) {
if (data.isWrong()) {
return "The data is wrong";
}
}
}, {
url: '/url/to/processing.php',
process: function(data) {
if (data != "OK") {
return "The data is not OK";
}
}
}];
// Now listen for the submit event
$("#form-id").on('submit', function(event) {
// Always stop the event
event.preventDefault();
// Do multiple ajax calls in one function call.
// Because the array is mutated inside multiAjax() (yeah, bad design but I've
// done this fast as an example), we slice() the array to get a new one
multiAjax(ajaxArray.slice(), function(error) {
if (error) {
// Show the error received
} else {
// submit the form the same way above
$("#form-id").off("submit").submit();
}
});
});
This is all untested code, but you get the point.
If one form submission is making two posts to the same PHP server, you should rethink the architecture instead of building complicated workarounds.
I would POST to a single PHP script that will do everything you need in the backend.
$.ajax({
type: 'POST',
url: '/url/to/all-processing.php',
... // send all the data needed by all processes
});
On the PHP side: all-processing.php
session_start();
require_once './process1.php';
require_once './process2.php';
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);
}
});
}
I have a piece of code I want to run after all the ajax is completed.
The function I wish to run is:
function autoContinueCart(){
$('.nextSection a:visible').click();
}
This click event runs validating script and moves to next section. Heres the main ajax.
$('#SubmitLoginOpc').click(function () {
$.ajax({
type:'POST',
url:authenticationUrl,
async:false,
cache:false,
dataType:"json",
data:'SubmitLogin=true&ajax=true&email=' + encodeURIComponent($('#login_email').val()) + '&passwd=' + encodeURIComponent($('#login_passwd').val()) + '&token=' + static_token,
success:function (jsonData) {
if (jsonData.hasError) {
//error stuff
}
else {
// update token
static_token = jsonData.token;
$('#dlv_label, #new_label').removeClass('new-l').addClass('logged-l'); // change label on delivery address section
updateNewAccountToAddressBlock();
// RESET ERROR(S) MESSAGE(S)
$('#opc_account_errors').html('').hide();
$('#opc_account_errors_invoice').html('').hide();
//It doesnt work here
//autoContinueCart();
}
},
//doesnt work here
// complete:autoContinueCart
});
return false;
});
I have put this function call in the success part, which I thought would work since it is synchronous. I also put it as complete and in .done function after the ajax call and it still runs before all the inside code is complete. The function updateNewAccountToAddressBlock(); basically makes another jquery ajax request with this type async:true, and returns json that is then used in about 10 functions or sub functions in the success call. One of these uses this data to fill out all the fields of a form. My function I am trying to call at the end is supposed to validate the info that is being populated. But no matter what I try, the validation is failing because the autoContineCart is being run before the fields are being populated. I also tried to use a callback like updateNewAccountToAddressBlock(updateAddressSelection); and then checked callback function inside of that and it also didnt work. Anyone have an idea what I could be doing wrong?
Since your call is already asynchronous, is it possible to move the processing code out of the ajax callback function? This would ensure that all of the ajax portion is complete before moving on to the processing piece.
Example:
$('#SubmitLoginOpc').click(function () {
$.ajax({
type:'POST',
url:authenticationUrl,
async:false,
cache:false,
dataType:"json",
data:'SubmitLogin=true&ajax=true&email=' + encodeURIComponent($('#login_email').val()) + '&passwd=' + encodeURIComponent($('#login_passwd').val()) + '&token=' + static_token
},
success: function(jsonData) {
$('#SubmitLoginOpc').data("some_key",jsonData);
}
//doesnt work here
// complete:autoContinueCart
});
jsonData = $('#SubmitLoginOpc').data("some_key");
if (jsonData.hasError) {
//error stuff
}
else {
// update token
static_token = jsonData.token;
$('#dlv_label, #new_label').removeClass('new-l').addClass('logged-l'); // change label on delivery address section
updateNewAccountToAddressBlock();
// RESET ERROR(S) MESSAGE(S)
$('#opc_account_errors').html('').hide();
$('#opc_account_errors_invoice').html('').hide();
//It doesnt work here
//autoContinueCart();
return false;
}
});
As the poster above said, Perhaps you could move some of the other ajax functions to run from the same js file, or move some of the Php functions to be run at the same time as the first call.
Ideally you shouldn't have to do another ajax request, because the php/whatever already has the info it needs from the client side. You should be able to send that data to other php/whatever scripts.
If you do need to do another ajax call, perhaps having the user wait a mandatory second, before you run the ajax call.
for instance:
$ajax.done(
// code
if (success)
{
setTimeout('foo', 5000);
$('#spinner').show();
}
function foo()
{
$('#spinner').hide();
//second ajax request
}
There is a page and I want periodically to make "background" ajax requests. So the page is loaded then it should send ajax requests in a certain amount of time.
I might use cron for that. I have never use previously so I'm wondering if it would fit for that task. Is there any other more simple way?
P.S. The time delay will be about 5 minutes.
Since there is essentially an unknown delay between the time you send out an AJAX request and the time you receive a complete response for it, an oftentimes more elegant approach is to start the next AJAX call a fixed amount of time after the prior one finishes. This way, you can also ensure that your calls don't overlap.
var set_delay = 5000,
callout = function () {
$.ajax({
/* blah */
})
.done(function (response) {
// update the page
})
.always(function () {
setTimeout(callout, set_delay);
});
};
// initial call
callout();
Cron is run on the serverside and you are using HTML and AJAX, so you should solve this issue in Javascript :-)
By using something like setInterval you can keep executing a function, your case might be something like polling a url via AJAX:
function updatePage(){
// perform AJAX request
}
setInterval(updatePage, 5000);
Depending on your rails version you may be able to use periodically_call_remote, otherwise you'll need the jquery alternative that #Bitterzoet described.
More info in this question.
You can send ajax request in four second like this:
setInterval(get_news, 4000);
function get_news(){
$.ajax('/dashboards/get_news', {
type: 'POST',
success: function(result) {
if(result > 0){
$('#div_1').text("See "+result+" new messages");
$('#div_1').show();
}
else{
$('#div_1').css('display', 'none');
}
},
error: function() {
// alert("Error")
}
});
}
Are you using jquery? If so, you can implement this method:
// first, you need asing a callback timer
var timeout = 300; //milliseconds
// this method contain your ajax request
function ajaxRequest() { //function to ajax request
$.ajax({
url: "/url/to/request/"
}).done(function(data) {
alert("response is: " + data);
});
}
$(document).on("ready", function(){
//this method will be called every 300 milliseconds
setInterval(ajaxRequest, timeout);
});
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
}
});