3

I have the following code:

$window.onbeforeunload = function (event) {
    event.preventDefault();
    // some asynchronous code 
};

I want the onbeforeunload event to wait until the asynchronous code is executed. Not sure if this can be achieved across all browsers supporting AngularJS.

georgeawg
  • 48,608
  • 13
  • 72
  • 95
  • Does this answer your question? [prevent onbeforeunload to close page in any case](https://stackoverflow.com/questions/30781070/prevent-onbeforeunload-to-close-page-in-any-case) – Tom Nov 04 '19 at 20:24

2 Answers2

4

Regardless of whether you are using AngularJS, or any other framework, delaying window unload until an async action completes is not something that modern browsers support anymore, as it creates a bad user experience.

However, assuming that the async thing you want to do is make an API request, then the modern solution is to use the navigator.sendBeacon() method instead. It is guaranteed to be sent in a non-blocking fashion by the browser, even after the window has been unloaded. It is a nicer solution for everyone.

Note that beacon requests have to be sent as POST requests, so your API needs to support this method for any endpoints you wish to use in an unload handler.

GregL
  • 37,147
  • 8
  • 62
  • 67
  • Thanks for the answer @GregL. As per the [link](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon), Internet Explorer is not supported. Is there anyway AngularJS handles this problem differently? – NISHANT KSHIRSAGAR Nov 04 '19 at 19:35
  • No, AngularJS is nothing more than some JS written by other people. It has no special privileges that allow it to bypass normal browser behavior. If you have to support IE, then I suggest that you send a synchronous AJAX request for IE only. Maybe it is old enough that it won't stop you from doing that. Everything else should use `sendBeacon()`. – GregL Nov 07 '19 at 18:59
  • I believe you could use the webworker for this. – Raf A. May 10 '21 at 14:25
  • @RafA. I'm not so sure this is true. From my attempts to understand the specs today, it seems like webworkers will be killed the moment their owning document is destroyed. The only type of worker that _maybe_ doesn't do this is the `ServiceWorker`, but I would definitely recommend testing this before relying on it. I still believe `navigator.sendBeacon()` is the most reliable way to do this if the browser supports it. – GregL May 11 '21 at 21:20
0

One can create a handler that looks at a spinner flag:

var spinnerFlag = false;

$window.addEventListener('beforeunload',unloadHandler);
$scope.$on("$destroy", function() {
    $window.removeEventListener('beforeunload',unloadHandler);
});

function unLoadHandler(e) {
  if (spinnerFlag) {
    // Cancel the event
    e.preventDefault();
    // Chrome requires returnValue to be set
    e.returnValue = '';
  };
});

Then one can set and clear the flag:

spinnerFlag = true;
var promise = promiseBasedAPI(arguments).finally(function() {spinnerFlag = false;});

This will set the flag before starting the asynchronous operation and clear the flag when the promise either succeeds or rejects.

The user will be prompted to confirm the page unload if the promise has not resolved.

For more information, see

georgeawg
  • 48,608
  • 13
  • 72
  • 95