7

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.

Community
  • 1
  • 1
index
  • 3,697
  • 7
  • 36
  • 55

3 Answers3

9

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.

UPDATE

The unload event is triggered when the page has unloaded.

UPDATE 2

To disable the Are you sure that you want to leave this page? popup try returning null from the beforeUnload callback function

UPDATE 3

Check this for cross-browser compatiblity

Community
  • 1
  • 1
nickaknudson
  • 4,769
  • 2
  • 15
  • 16
  • Sorry if my reply was a bit uber late. I tried adding the whole ajax block to beforeunload before but it always asks a question first of 'Are you sure you want to leave this page?' with an [object object] as added message. I searched before and I think that was the purpose of beforeunload... how can I remove that? – index Dec 27 '12 at 02:23
  • And thanks for that info that unload event is triggered when the page HAS unloaded already. – index Dec 27 '12 at 02:40
  • Try returning `null` from your `beforeUnload` function http://stackoverflow.com/questions/1119289/how-to-show-the-are-you-sure-you-want-to-navigate-away-from-this-page-when-ch – nickaknudson Dec 27 '12 at 06:22
  • Yup. I did played around with it throwing in a number of values as well - false, undefined then null, and I've updated my post about that particular fix as well. I was just wondering, would it work on every browser (haven't got the time to test it out yet)? – index Dec 27 '12 at 07:04
  • Check this for cross-browser compatibility http://jonathonhill.net/2011-03-04/catching-the-javascript-beforeunload-event-the-cross-browser-way/ – nickaknudson Jan 08 '13 at 22:56
4

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.

SaschaM78
  • 4,376
  • 4
  • 33
  • 42
  • Have you experiences any browser that window.onbeforeunload is problematic in? – akamaozu Dec 26 '12 at 18:51
  • No, but I haven't tested Opera and browsers running on OSX. Chrome, IE and all recent versions of FF do support it. – SaschaM78 Dec 26 '12 at 23:09
  • Sorry if my reply was a bit uber late. I tried adding the whole ajax block to beforeunload before but it always asks a question first of 'Are you sure you want to leave this page?' with an [object object] as added message. I searched before and I think that was the purpose of beforeunload... how can I remove that? – index Dec 27 '12 at 02:23
  • This normally happens if the bound function returns a value, may it be boolean, string or whatever. So do not return anything or possibly return null. – SaschaM78 Dec 27 '12 at 08:41
3

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.

Troy Alford
  • 26,660
  • 10
  • 64
  • 82
Techie
  • 44,706
  • 42
  • 157
  • 243