9

I'm using a AutoSave feature on an online editor.

When an user leaves the page (detected with unload or beforeunload event), I'm sending a AJAX request (async = false) to save the data.

I have a problem in Firefox et sometimes in Chrome because that serie of events is happening :

  • event fired
  • request send
  • the page change and the user is disconnected
  • request analysed by the server => problem !
  • request response received by browser

Of course since the user has been disconnected the "save" request can't be handled.

Is there a way, compatible with all browsers, to wait for the response of the AJAX call, before the page actually changes ?

tshepang
  • 12,111
  • 21
  • 91
  • 136
Loïc Février
  • 7,540
  • 8
  • 39
  • 51

5 Answers5

11

ori's answer is correct and complete.

But judging from your case you could use a workaround.

There are two JavaScript features you might be interested in: localStorage and sessionStorage (it's the same except the second one is cleared on browser close, so you probabli will choose the first)

The idea is to save data to localStorage with some metadata stating if changes were saved. If the user leaves the page but goes to another page in your service, or even returns later - you can send the data again with some information that it was not saved due to page unload.

Proof of concept code:

$(window).bind('unload', function() {
    localStorage.setItem('unsavedData',data);
    localStorage.setItem('unsaved',true);
});

$(document).ready(function(){
    if(localStorage.getItem('unsaved')){
       //ajax send 
       localStorage.setItem('unsaved',false);
    }
});

[edit]

I have been successfully using JSONP with unload and it seemed to work most of the times, but I haven't tested it under load and on slow network.

naugtur
  • 16,827
  • 5
  • 70
  • 113
  • 1
    A good work around, but it would require HTML5, no? This may or may not be an issue with older browsers. I like it though +1 – one.beat.consumer Jan 19 '12 at 06:07
  • 1
    localStorage is as old as IE8. – naugtur Jan 19 '12 at 17:06
  • 1
    Thanks, nice idea, I've implemented it and looks good so far. I'm using jStorage script (http://www.jstorage.info/), this gives IE6+ support too – Pēteris Caune Jan 20 '12 at 14:56
  • To support old browsers you need to put JSON support in - hope you did. Except for that it looks really nice and does not fallback on cookies, which is great! – naugtur Jan 20 '12 at 20:03
6

No. You can only display a confirm dialog to the user:

$(window).bind('beforeunload', function() {
    // AJAX

    return 'STRING';
});

The STRING will be displayed in the dialog, and then you might have time for the reponse to come back before user reacts.

But that's the only way you can block a page from unloading, hence the ajax response will not be received.

ori
  • 7,817
  • 1
  • 27
  • 31
  • 1
    +1 - in addition to above, your message can alert the user about unsaved changes and give them the opportunity to stay on the page and click save themself. There is no guaranteed way for AJAX sync or async on page unload. Some browsers will, some will do "best effort", some will just terminate the browser window when closing the browser process (no chance for anything). – BenSwayne Jan 17 '12 at 23:27
0

What about a fixed transparent div across the top of your page with a hover event to fire the save? Just thinking form a creative point of view... Keep the save you have now, but as a failsafe, I'm thinking if the average user is going to navigate away, first they will move the mouse to the address bar, back button, or close button. If you capture the top of the DOM Window, maybe get a few more successful last-minute saves?

Also, you could push the changes on a setTimeout() but it sounds like you're going for something more finite than both of my solutions.

Kyle Macey
  • 8,074
  • 2
  • 38
  • 78
0

Turning async to false would be easier thing to do.

Otherwise you could call server with async:true and when it returns either successfully or with error you can raise a custom event for logout/redirect/error message.

A hovering transparent div can be used to keep user waiting til the server responds.

Udayan
  • 45
  • 4
  • Not helpful if user closes a tab or navigates to another URL. The question was not about persuading the user to stay after clicking save, but about saving after he decided not to stay. – naugtur Jan 18 '12 at 21:20
  • May be I misunderstood the question, I was talking about saving data when user hits logout link but same thing can be done when s/he navigates away from the page. The point is to sync unsaved data back to server when needed you can do it periodically (like some mail services do eg. Gmail) or on user interaction. – Udayan Jan 19 '12 at 06:54
  • That's what OP is doing already, but it fails due to specifics of the `unload` event – naugtur Jan 19 '12 at 17:04
0

I am using onbeforeunload for something similar, but my data payload is quite small (a guid), and I don't need any return value, so it's fire and forget. It works around 95% of the time, but different browsers implement onbeforeunload, onunload, etc differently.

You could pop another window with the unsaved data, then close that window once your request has fired, but the key element here is 'pop' - chances are, that'll be blocked. T local storage answer above could be used by this.

Of course, the first solution - ask user, then let them save is probably the best. Perhaps they're closing to prevent saving any changes since the last save?

jpda
  • 738
  • 5
  • 16