Now the problem below happens only with Safari. Chrome, Opera, IE all work fine.
I have tried:
function do(x){
$.ajax({url: "next.php",
type: "POST",
data: {'cand': x},
success: leave()});
}
function leave(){window.location = "next.php";}
This:
$.post("next.php", {'cand': x});
window.location = "next.php";
And the other two combinations of the above as well. I noticed that when I don't leave the page, the ajax/post request both work, but when I leave the page, they dont. What I mean is when I use the window.location command. As in, the user will leave the page but the post request will not work. Again, this only happens in Safari. I dont't have a Safari browser immediately in front of me so I cannot test it thoroughly.
Can anyone who has any clue let me know what's going on?
If you do this: success: leave() (as in your first example) then you evaluate leave function immediately, and the change of location occurs concurrently to the ajax call. Some browsers will complete the ajax call, some won't.
Instead, do this: success: leave. This will call leave function after the ajax call.
You could try the following, because here the function() is only called after the PHP execution is completed. In your case, it could be that the callback is executed before the Ajax is completed. In that case you could maybe use a little work around and use setTimeout() to wait a short time before leaving.
$.post('next.php', {cand: x}, function() {
// Callback function: called after php script is completed
// setTimeout waits 500ms before leaving
setTimeout(function(){
leave();
}, 500);
})
Related
I'm trying to make a spinner button that will spin while I make an AJAX request and stop when the answer is received.
I've got the AJAX handled but the spinning doesn't seem to work with the following code:
function refresh (id){
var iconElem = document.getElementById("spinner" + id);
iconElem.classList.add('fa-spin');
sleep(5000);
var buttonRefresh = document.getElementById("refreshButton" + id);
buttonRefresh.classList.remove("fa-spin");
};
Note : I have replaced the ajax function with a sleep (implemented elsewhere, but it works like like it should) since I am in a non-php environment.
What happens here is that the the class "fa-spin" is being added while the sleep is over, even though it comes after in the code... Am I missing some kind of "refresh" that I need to execute in order to make the added class effective ?
You need to stop the spinning in the completion callback of the ajax call as it is a async call.
What you are doing here is starting and then immediately stopping the spinner before the ajax call even finishes.
$.ajax({
url: "test.html",
cache: false,
success: function(html){
// stop the spinner here
}
});
Here is the simplest solution with a callback:
function sleep(callback,timeout){
setTimeout(callback,timeout)
}
sleep(() => {
//stop spinner here
},200)
Anyways, I suggest you to read more here
If you are doing an ajax request, you can also use the async:false header to make your request synced, and then your code should work.
Changes to the style or content of the document become effective only when the JavaScript function finishes and returns to the main event loop. Therefore, assuming your sleep() function works as expected (by doing a busy wait or something like that, although that is not actually sleeping), you can only see the total effect of all changes when the function returns. If you follow the advice of the other answers and remove the style in the callback of the AJAX call, you will be fine.
I put a sleep(5) in ajax.php page. I need the code returned to start another function group. It is also using ajax. My first ajax call looks like this:
$.ajax({
url: '/ajax.php',
data: {
id : code
} ,
type: 'POST',
async:false, //<<< here
cache: false,
beforeSend: function(){
$('#loading').dialog();
},
success: function(data){
console.log(data.result);
$('#loading').dialog('close');
initAnotherFunctionGrop(data.result);
},
error: function(){
$('#loading').dialog('close');
}
});
Why I cannot show to the loading message in IE and Chrome? Just Firefox is working with that.
Asynchronous code is best. Synchronous code can hang your browser, which makes it a bad idea in the case of ajax, where the speed of the ajax request depends on factors beyond the users computer and the browser. You don't want the users machine to hang, so avoid it. Instead try something like this.
function a(passedData){
return $.ajax({
url : '/ajax.php',
data : passedData
});
}
function b(passedData){
return $.ajax({
url : '/ajaxB.php',
data : passedData
});
}
$.when(a(data),b(data)).then(function(successDataForA,successDataForB){
//Do code after all asynchronous ajax calls are done.
//As a whole this is still asynchronous so other things can still run
},function(failA,failB){
//This fail callback is not necessary but here it is if needed
});
Use this
$(document).ready(function () {
$('#ajaxloading').hide() // hide it initially
.ajaxStart(function () {
$(this).show();
})
.ajaxStop(function () {
$(this).hide();
});
});
here "ajaxloading" is the Id of the DIV, which you want to display or hide. U can put any content inside this div
If your loading image is gif image, then its hard to show it in IE and chrome, as these browsers stop any changes to DOM component while synchronous call and once the code is executed it shows all the changes.
You can test it by putting an alert box just after you load an image.
$('#loading').dialog();
alert('loading image');
Once alert it popup, you can now see loading image in both IE and chrome as alert stop thread execution until a response is given by user.
Read this link:
[https://stackoverflow.com/questions/11946828/loading-gif-image-is-not-showing-in-ie-and-chrome]
I've had problems in the past getting IE to show a "loading..." message during an Ajax call even with an async call (which is what I'd certainly recommend you use), where the same code did work in FF.
The workaround that has worked for me with IE (and done no harm in FF) is to do something like this:
$('#loading').dialog();
setTimeout(function() {
$.ajax(...);
},1);
That is, show the "loading" message then postpone the Ajax call by use of setTimeout() - this gives the browser a moment to redraw the page after the current JS finishes but before the timeout kicks in.
But of course if you're doing a synchronous request you presumably have additional code that you want to run after the $.ajax() method using its results, so you'd need to move all of that into the function you pass to setTimeout() (or call it from there, anyway).
Is there an event in javascript that I could bind some sort of listener to that will tell me when all javascript/jQuery/Ajax is done executing on the page? The page will not be loading/unloading/reloading, etc between the time the execution begins and the time that I need the listener to "listen", so those events don't work. The page literally is not doing anything. The button is clicked and some javascript functions fire which contain Ajax calls to web services. After all have finished, I want to change window.location. But window.location is changing before the web services have finished in my case.
Currently using setTimeout to achieve this, but as sometimes the code needs more time to run than normal, sometimes the window.location is firing before all the other javascript has finished. Simply put
<input type = "button"... onclick="doThis();";
function doThis() {
try{
//Contains AJAX calls to web services which is mainly what screws up my timing since it may still be trying to execute stuff when the redirect statement happens
}
catch (e) {
}
//Currently doing setTimeout(redirect, 10000);
//Would like to simply detect when all of the above is done and then redirect.
}
Edit: Left out a crucial piece of info. The AJAX calls are in a for loop. The use of variables and success callbacks hasn't been working so well for me as by the time my success callback is executing, my variables have taken on new values in the for loop.
What you are trying to achieve is a classical concurrent programming problem. It is solved by the use of a barrier.
To put it simply, you need to:
Count how many calls you've done.
Set a callback on all AJAX completion events.
Make that callback decrement the number of calls.
The callback checks whether the number of calls has reached zero or not. If yes, then your final code (here, redirect) is called.
The actual implementation is left as an exercise to the reader :)
Hint: embed AJAX calls into a function that handles all counter incrementation and callback setting.
What I do:
Create a variable that represents the number of outstanding AJAX calls.
Before making an AJAX call, increment the variable.
At the end of the code that completes an AJAX call, call a function (e.g. ajaxComplete).
ajaxComplete should decrement the count. When it reaches zero, you know all your calls are complete.
Assuming you're using jQuery.ajax, it sounds like you're looking for ajaxStop.
Why don't you try using something like the Underscore library's after function in the callbacks?
var done = _.after(3, function() {
window.location = 'http://example.com';
});
$.ajax({
url: '/tic',
success: function() {
done();
}
});
$.ajax({
url: '/tac',
success: function() {
done();
}
});
$.ajax({
url: '/toe',
success: function( data ) {
done();
}
});
You should check for the response from AJAX call, and only in that response do redirect. This way you will avoid doing redirect while AJAX was still executing.
I have a function called:
function callAjax(url, data) {
$.ajax(
{
url: url, // same domain
data: data,
cache: false,
async: false, // use sync results
beforeSend: function() {
// show loading indicator
},
success: function() {
// remove loading indicator
}
}
);
}
In the code, I call "callAjax" X number of times and I want to update the data synchronously. It is done as expected, but one problem: the loading item doesn't show in beforeSend function. If I turn async to true, it works but the updates aren't synchronously done.
I've tried several things with no success. I tried putting the loading indicator before the ajax call like this:
function callAjax(url, data) {
// show loading div
$.ajax(
{
// same as above
}
);
}
But for some reason it doesn't want to show the loading indicator. I notice a strange behavior when I put an "alert" in the beforeSend and the loading indicator appears in that case, but I rather not pop up a message box.
Got any ideas?
Making a synchronous call like that is like putting up an "alert()" box. Some browsers stop what they're doing, completely, until the HTTP response is received.
Thus in your code, after your call to the "$.ajax()" function begins, nothing happens until the response is received, and the next thing as far as your code goes will be the "success" handler.
Generally, unless you're really confident in your server, it's a much better idea to use asynchronous calls. When you do it that way, the browser immediately returns to its work and simply listens in the background for the HTTP response. When the response arrives, your success handler will be invoked.
When you do the blocking I/O the program is halted until the the input is received, in JS words when doing a synchronous call, the program halts and browser window freezes (no painting can be done) until the response is received. In most cases doing syncronus calls and any kind of blocking I/O can be avoided. However imagine your doing a progress bar in java or any other programming language, you have to spawn a different thread to control the progress bar, I think.
One thing to try in your case, is to call the ajax call after a time delay
//loading div stuff,
//if your doing some animation here make sure to have Sufficient
//time for it. If its just a regular show then use a time delay of 100-200
setTimeout( ajaxCall, 500 );
EDIT ajaxcall in setTimeout, Example
This is what you are looking for - .ajaxStart()
It will be triggered when any ajax event starts
http://api.jquery.com/ajaxStart/
They even give a specific example similar to what you are trying to accomplish:
$("#loading").ajaxStart(function(){
$(this).show();
});
You can then use the .ajaxStop() function
$("#loading").ajaxStop(function(){
$(this).hide();
});
Every 3 seconds I make an AJAX POST request to get the status of a process. This works great.
When the process reaches 100% a call back function executes(indicated below) to add new elements to the page and then it cancels the setTimeout method that use to continuously get the progress every 3 seconds. However, I have been told by my users it sometimes fails to cancel and the new elements are not added to the page and I've been that it get stuck at showing "100%".
I have tested this again and again and it never gets stuck for me. The code also looks ok, but my JavaScript skills are not great so I was hoping someone could point out if there is potential of this problem happening?
I have commented the code, apologies its very long. I have tried to reduce it.
function convertNow(validURL){
startTime = setTimeout('getStatus();', 6000);
//AJAX CALL TO RUN PROCESS
$.ajax({
type: "GET",
url: "main.php",
data: 'url=' + validURL + '&filename=' + fileNameTxt,
success: function(msg){
//ON SUCCESS CLEAR SETTIMEOUT AND SHOW ELEMENTS (text)
clearTimeout(continueTime);
clearTimeout(startTime);
$("#loading").hide("slow");
$("#done").html("Done");
}//function
});//ajax
}//function convertNow
function getStatus(){
//AJAX CALL TO GET STATUS OF PROCESS
$.ajax({
type: "POST",
url: "fileReader.php",
data: 'textFile=' + fileNameTxt,
success: function(respomse){
textFileResponse = respomse.split(" ");
$("#done").html("Processing...");
}
});//ajax
clearTimeout(continueTime);
if(textFileResponse[0]=='100.0%'){
clearTimeout(continueTime);
}
else{
clearTimeout(startTime);
continueTime = setTimeout('getStatus();', 3000);
}
}
There's probably a parsing error in the textFileReponse[0]=='100.0%' in some edge cases, with the value in the response not equaling exactly 100.0% (maybe there's extra whitespace, or maybe there are some minor differences on some platforms, etc...). This would cause the code to fall through to the else {} block, and your getStatus function would be queued up again.
EDIT: Given the thread in the comments, it's also an equal likelyhood that there's a race condition going on between the two blocks of Ajax code. (just putting this here for the benefit of readers). END EDIT
What you probably want, in addition to resolving the parsing, however, is to use setInterval(), with only one timer, instead of a startTime and continueTime timer. setTimeout executes only once, whereas setInterval repeats every x milliseconds, so you'd need only one. To cancel a setInterval, use clearInterval.