Window.unload triggers post after unload - javascript

I am trying to do a post to server before unloading a page and I followed this and it's working fine. My problem is the $.post on window.unload is triggered after it has unloaded. I tried it with a signout link and checking on my logs, I get the following:
Started GET "/signout" for 127.0.0.1 at 2012-11-22 00:15:08 +0800
Processing by SessionsController#destroy as HTML
Redirected to http://localhost:3000/
Completed 302 Found in 1ms
Started GET "/" for 127.0.0.1 at 2012-11-22 00:15:08 +0800
Processing by HomeController#index as HTML
Rendered home/index.html.erb within layouts/application (0.4ms)
Rendered layouts/_messages.html.erb (0.1ms)
Completed 200 OK in 13ms (Views: 12.9ms)
Started POST "/unloading" for 127.0.0.1 at 2012-11-22 00:15:08 +0800
Processing by HomeController#unloading as */*
Parameters: {"p1"=>"1"}
WARNING: Can't verify CSRF token authenticity
Completed 500 Internal Server Error in 0ms
NoMethodError (undefined method `id' for nil:NilClass):
app/controllers/home_controller.rb:43:in `unloading'
First part is the signout and then user gets redirected to root then it runs the post ('/unloading').
Is there a way to make the '/unloading' execute first then execute whatever the unload action was?
I have this as my jquery post
$(window).unload ->
$.ajax {
async: false,
beforeSend: (xhr) ->
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))
, url: '/unloading'
, type: 'Post'
, data: {
p1: '1'
}
}
Update
So I did transfer the ajax request to beforeunload and it was working but I had to do a return null to remove the dialog box appearing because if I don't, the ajax was still triggering on popup of dialog (even without answering "yes/no i want to leave this page"). Result is this:
window.onbeforeunload ->
$.ajax {
async: false,
beforeSend: (xhr) ->
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))
, url: '/unloading'
, type: 'Post'
, data: {
p1: '1'
}
}
return null
Also, I have only tried it with Chrome for now and it's working as expected. Yet to try on other browsers.

Try the beforeUnload event
The exact handling of the unload event has varied from version to
version of browsers. For example, some versions of Firefox trigger the
event when a link is followed, but not when the window is closed. In
practical usage, behavior should be tested on all supported browsers,
and contrasted with the proprietary beforeunload event.
https://developer.mozilla.org/en-US/docs/DOM/window.onbeforeunload
UPDATE
The unload event is triggered when the page has unloaded.
https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Synchronous_and_Asynchronous_Requests#XMLHttpRequests_being_stopped
UPDATE 2
To disable the Are you sure that you want to leave this page? popup try returning null from the beforeUnload callback function
How to show the "Are you sure you want to navigate away from this page?" when changes committed?
UPDATE 3
Check this for cross-browser compatiblity
http://jonathonhill.net/2011-03-04/catching-the-javascript-beforeunload-event-the-cross-browser-way/

As #NickKnudson suggested, use the "beforeUnload" event to post back form data before the window is unloaded:
window.onbeforeunload = function() {
$.ajax {
async: false,
beforeSend: (xhr) ->
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))
, url: '/unloading'
, type: 'Post'
, data: {
p1: '1'
}
}
}
Ran into exact the same situation about two weeks ago, switching to beforeUnload solved the problem.

The problem is that the window's unload event does not wait for AJAX calls (which are asyncrhonous) to complete prior to closing the window. In addition, jQuery doesn't seem to have built-in handling for the beforeunload event - which is why you will need to revert to native JS code to handle this. See below:
(Note: Written in CoffeeScript)
window.onbeforeunload = function() {
$.ajax {
async: false, // Important - this makes this a blocking call
beforeSend: (xhr) ->
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))
, url: '/unloading'
, type: 'Post'
, data: {
p1: '1'
}
}
};
onbeforeunload - An event that fires before the unload event when the page is unloaded.
Also see this Google Forum discussion about this topic.

Related

Ajax call on onbeforeunload event doesn't work (Firefox only)

I need to make an Ajax call when a user leaves my page.
I don't need to wait for the end of the call, I just need to notify my server with a kindly "hey, user XXX is leaving the page", without notifying the client.
Here is what I've done so far :
window.onbeforeunload = function () {
$.ajax({
type: "POST",
url: myURL,
contentType: "application/json; charset=utf-8",
data: JSON.stringify({ xxx: xxx, yyy: yyy })
});
}
This perfectly works with Chrome and Edge, but this event is not raised on Firefox.
What I've done so far :
I tried this SO answer, as the author claims it works and has a good score, but once again, my ajax call is not fired.
Add async: false without any success
Also tried to use beforeunload instead of onbeforeunload
Can anyone explain me how to fire my Ajax call when an user leaves a page, no matter he uses Chrome, Edge or Firefox ?
Thanks in advance ?

How can i stop hanging page when a request is send via Ajax

I am facing a serious issue... Whenever i use Ajax to send a request and get an response my browser got hanged.. and show no loading etc...
But when i response is retrieved from the Ajax then browser and page again start working...
Below is the code that i used.....
function ShowContestStatus(contestID)
{
$("#showContestDetails").html('<div class="loadercontest"><img src="assets/images/loading.gif">Loading Contest....</div>');
$("#RadioGroup1_0, #RadioGroup1_1, #RadioGroup1_2").prop('disabled', true);
$.ajax({
url:"process/processMyContest.php",
type:'POST',
cache:false,
async:false,
data : {act : 'showcontest', cid : contestID },
success:function(result)
{
$("#showContestDetails").html(result);
$("#RadioGroup1_0, #RadioGroup1_1, #RadioGroup1_2").prop('disabled', false);
}
});
}
Please help me on this... i want to get the same response as on other websites when you send a request and they are using ajax the page neither hanged and also each processing like scrolling etc is visible ......
So please suggest me good ideas.... so i can get rid of it and make my ajax smooth for page without effecting and irritate the other person by hanged...
Thanks in advance...:)
The problem is async:false... Since your ajax request is synchronous the script execution will wait for the request to complete to continue..
Since browser uses a single threaded execution pattern(either it will execute script or repaint or wait for user events at a time- not all at the same time), your browser tab will stop listening to user(so it will look like it is hanged)
function ShowContestStatus(contestID) {
$("#showContestDetails").html('<div class="loadercontest"><img src="assets/images/loading.gif">Loading Contest....</div>');
$("#RadioGroup1_0, #RadioGroup1_1, #RadioGroup1_2").prop('disabled', true);
$.ajax({
url: "process/processMyContest.php",
type: 'POST',
cache: false,
//remove async: false,
data: {
act: 'showcontest',
cid: contestID
},
success: function (result) {
$("#showContestDetails").html(result);
$("#RadioGroup1_0, #RadioGroup1_1, #RadioGroup1_2").prop('disabled', false);
}
});
}
Ajax.async
By default, all requests are sent asynchronously (i.e. this is set to
true by default). If you need synchronous requests, set this option to
false. Cross-domain requests and dataType: "jsonp" requests do not
support synchronous operation. Note that synchronous requests may
temporarily lock the browser, disabling any actions while the request
is active. As of jQuery 1.8, the use of async: false with jqXHR
($.Deferred) is deprecated; you must use the success/error/complete
callback options instead of the corresponding methods of the jqXHR
object such as jqXHR.done() or the deprecated jqXHR.success().
Make async:true for making the browser listen other events while running the ajax code.

Efficient way of passing data and calling background script in PHP

I have a page where I show 5 questions to a user and when he clicks on Next 5 link I am sending the score of current page onbeforeunload() to the script updateScore() asynchronously using jQuery AJAX and when the call is successful the next 5 questions are displayed.
window.onbeforeunload=function()
{
$.ajax({
type: "POST",
url: "updateScore.php",
data: "pageScore="+score,
cache: false,
timeout:5000,
async:false
});
}
But the problem is that on slow connections,it might hang the browser for a while until AJAX call returns successfully.When I tried async:true(default) the next page is loaded first without making call to updateScore.php.It might be due to the fact that connection is fast in localhost hence giving no time for the AJAX call to complete.This was the reason I used async:false.Will it happen (making no AJAX call) if I use async:true in practical case as well?If yes, is there a way to come around this problem?
I advice you to change your code a bit.
Make ajax request on "click" event, and redirect user inside ajax callback function.
Like this:
$('#mybutton').on('click', function()
{
$('#pleasewait').show();
$ajax({
type: "POST",
url: "updateScore.php",
data: "pageScore="+score,
success: function() { document.location="nextpage.php" }
});
}

Ajax call not working until user interaction in IOS

I am developing an application using phonegap and jQuery and I am facing a problem when performing ajax requests on iOS. I do the request , the php on my server receives the information and echo the correct answer. Turns out my app does not 'get' the information until I interact somehow with the screen (scrolling for example) or really wait too long ( over a minute ). This problem evolved, in the beginning happened just after a few requests and now the first ajax already shows it . Another thing I noticed was, when taking out all ( or almost all ) javascript and/or css ( weird ) the problem disappears as if it was something with the phone memory . When doing the request using async : false , the problem also disappears! It happens on the iPhone 4 . Was tested on Android and PC (Chrome and Mozilla Firefox ) and it worked fine.
The weirdest thing is that when I interact with the screen , the answer appears, it do not wait a second, it is almost instantaneous ... as if the answer was already there, but not showing up for some reason.
Ps: The error alert don`t appears.
jQuery.ajax({
type: 'GET',
url: 'url',
crossDomain: true,
data: {
data: data
},
error: function() {
alert('error');
}
}).done(function(data) {
alert(data);
});
http://api.jquery.com/jQuery.ajax/
if you are wanting a funciton to be triggered on response i would use the complete instead of done.
My guess is you are not cancelling the click action and the page is refreshing
$(".yourSelector").on("click",function (evt) {
evt.preventDefault();
//your ajax call
});

Problem with jQuery.ajax with 'delete' method in ie

I have a page where the user can edit various content using buttons and selects that trigger ajax calls. In particular, one action causes a url to be called remotely, with some data and a 'put' request, which (as i'm using a restful rails backend) triggers my update action. I also have a delete button which calls the same url but with a 'delete' request. The 'update' ajax call works in all browsers but the 'delete' one doesn't work in IE. I've got a vague memory of encountering something like this before...can anyone shed any light? here's my ajax calls:
//update action - works in all browsers
jQuery.ajax({
async:true,
data:data,
dataType:'script',
type:'put',
url:"/quizzes/"+quizId+"/quiz_questions/"+quizQuestionId,
success: function(msg){
initializeQuizQuestions();
setPublishButtonStatus();
}
});
//delete action - fails in ie
function deleteQuizQuestion(quizQuestionId, quizId){
//send ajax call to back end to change the difficulty of the quiz question
//back end will then refresh the relevant parts of the page (progress bars, flashes, quiz status)
jQuery.ajax({
async:true,
dataType:'script',
type:'delete',
url:"/quizzes/"+quizId+"/quiz_questions/"+quizQuestionId,
success: function(msg){
alert("success");
initializeQuizQuestions();
setSelectStatus(quizQuestionId, true);
jQuery("tr[id*='quiz_question_"+quizQuestionId+"']").removeClass('selected');
},
error: function(msg){
alert("error:" + msg);
}
});
}
I put the alerts in success and error in the delete ajax just to see what happens, and the 'error' part of the ajax call is triggered, but WITH NO CALL BEING MADE TO THE BACK END (i know this by watching my back end server logs). So, it fails before it even makes the call. I can't work out why - the 'msg' i get back from the error block is blank.
Any ideas anyone? Is this a known problem? I've tested it in ie6 and ie8 and it doesn't work in either.
thanks - max
EDIT - the solution - thanks to Nick Craver for pointing me in the right direction.
Rails (and maybe other frameworks?) has a subterfuge for the unsupported put and delete requests: a post request with the parameter "_method" (note the underscore) set to 'put' or 'delete' will be treated as if the actual request type was that string. So, in my case, i made this change - note the 'data' option':
jQuery.ajax({
async:true,
data: {"_method":"delete"},
dataType:'script',
type:'post',
url:"/quizzes/"+quizId+"/quiz_questions/"+quizQuestionId,
success: function(msg){
alert("success");
initializeQuizQuestions();
setSelectStatus(quizQuestionId, true);
jQuery("tr[id*='quiz_question_"+quizQuestionId+"']").removeClass('selected');
},
error: function(msg){
alert("error:" + msg);
}
});
}
Rails will now treat this as if it were a delete request, preserving the REST system. The reason my PUT example worked was just because in this particular case IE was happy to send a PUT request, but it officially does not support them so it's best to do this for PUT requests as well as DELETE requests.
IE 7 and 8 do not support DELETE and PUT methods. I had a problem where IE7,8 would not follow a 302 redirect and IE would use the DELETE or PUT method for the location that it was supposed to redirect to (with a get.)
To ensure that IE7 and 8 work properly, I would use a POST with the parameters:
data: {'_method': 'delete'}
Take a look at your type attribute type:'delete'
jQuery documentation on type:
The type of request to make ("POST" or "GET"), default is "GET". Note: Other HTTP request methods, such as PUT and DELETE, can also be used here, but they are not supported by all browsers.
I would instead try and include this with your data and look for it on the server-side, like this:
data: {'action': 'delete'},

Categories