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

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 ?

Related

$(window).on('unload', ... prevents url change

I am trying to execute a function when the user tries to change url, close tab etc. The issue is that when user refreshes/clicks on hyperlink/changes url, the url is updated but the page remains exactly the same.
The problem is especially severe with latest Firefox (did not notice it before for some reason). Chromium on the other hand will wait a few seconds before closing the tab, giving it an awkward, laggy feeling.
The code as it is:
$(window).on('unload', function() {
$.ajax({
type: 'POST',
url: 'ajax/whattodo.php',
async: false,
data: {
method: 'iquit',
exitdata1: exitdata1,
exitdata2: exitdata2
}
});
});
If I remove "async:false" the problem is no longer there. But neither are functions executed. What to do?
The page not redirecting is especially annoying, and confusing for the user.

window.open doesn't work in http post angular

Here's my code:
$rootScope.http({
url: myUrl,
method: "POST",
data: "",
}).success(function (data) {
alert(data.uri); //for test, and I see correct uri shows up here.
window.open(data.uri, ''); return false; //window doesn't open.
});
The window.open doesn't work inside the .success, but it does work outside the http post method. Something is wrong when comes to callback function. I met very same issue in $.ajax and fixed it. But same solution doesn't work here for angular.
We faced the similar problem before and the reason is simple; in the most of the modern browsers, browsers will not allow the window.open() call which are not the direct result of user activity.
Here, your window.open() is being triggered in an asynchronous call which is not being called by a user action, for example: clicking on a link or a button.
You can fix this problem by disabling the popup blocker but we have to notify the user that their popup blocker is enabled. For that, you can do something like this:
$rootScope.http({
url: myUrl,
method: "POST",
data: "",
}).success(function (data) {
$rootScope.popupWindow = window.open(data.uri, '');
$timeout(function() {
// Check if popup blocker is enabled by verifying the height of the new poup
if (!$rootScope.popupWindow || $rootScope.popupWindow.outerHeight === 0) {
alert("Please disable the popup blocker");
}
}, 1000);
});
(Note: I've tested this is a browser, not sure in the mobile but this should work)

Window.unload triggers post after unload

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.

IE Explorer 9 not rendering until after ajax/json function has complete

Basically I have this code. I am trying to simply update a div but the first innerHTML call either does not work or never renders in the browser.
The second one does work though which appends "Complete" once the ajax call is complete. I'm sure it has something to do with the ajax call but I don't see why this is happening because in Firefox there is no issue. Does anyone know what is wrong or if there is a bug in firefox or something? Why would IE even be waiting to render the innerHTML call. Shouldn't the div be updated right after the call or does IE explorer wait a bit?
document.getElementById("status").innerHTML = '<div>Loading</div>';
$jQuery.ajax({
type: "POST",
url: urlValue,
data: parameters,
cache: false,
async: false,
dataType: "json"
});
document.getElementById("status").innerHTML = '<div>Complete</div>';
Why not just do it asynchronously?
var status = $('#status');
status.html('<div>Loading</div>');
jQuery.ajax({
type: "POST",
url: urlValue,
data: parameters,
cache: false,
dataType: "json",
success: function() {
status.html('<div>Complete</div>');
}
});
try to execute those code on load complete.
Possibly in moment when
document.getElementById("status").innerHTML = '<div>Loading</div>';
executed DOM is not ready for accessing it.
On DOM ready - putting "Loading Value"
Making ajax request ("loading is displayed till it will ends")
Once it will ends, setting "Complete"
Anyway till DOM is ready you can not change it. Except document.write, but it's little bit another story.
Probably that will help
setTimeout(function(){document.getElementById("status").innerHTML = '<div>Loading</div>';},0);
ajax post request ...

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