60

I tried the following code to get an alert upon closing a browser window:

window.onbeforeunload = confirmExit;
function confirmExit() {
  return "You have attempted to leave this page.  If you have made any changes to the fields without clicking the Save button, your changes will be lost.  Are you sure you want to exit this page?";
}

It works, but if the page contains one hyperlink, clicking on that hyperlink raises the same alert. I need to show the alert only when I close the browser window and not upon clicking hyperlinks.

Paolo Forgia
  • 6,572
  • 8
  • 46
  • 58
user42348
  • 4,181
  • 28
  • 69
  • 98
  • 2
    Voted to reopen. The linked duplicate does not answer the question, but the answers here do. – Heinzi Jan 22 '13 at 12:50
  • FWIW, I will come stab you in the pinky toe if you put this behavior into any app I have to use. Hijacking the browser is a godawful solution to this problem. Can't you just use AJAX or something and auto-save their state? – Graham Jan 22 '13 at 13:26
  • 4
    I disagree with Graham--sometimes a warning/confirmation is all you need. Granted this can (and often is) abused by sites trying to keep you from leaving, but employed properly it can be much appreciated, for example, if you forget to post something. – devios1 Jan 23 '13 at 18:13
  • You will still have problems if you want to refresh the page, even if you disable the anchor events. – ROMANIA_engineer Dec 10 '15 at 15:46

4 Answers4

51

Another implementation is the following you can find it in this webpage: http://ujap.de/index.php/view/JavascriptCloseHook

<html>
  <head>
    <script type="text/javascript">
      var hook = true;
      window.onbeforeunload = function() {
        if (hook) {
          return "Did you save your stuff?"
        }
      }
      function unhook() {
        hook=false;
      }
    </script>
  </head>
  <body>
    <!-- this will ask for confirmation: -->
    <a href="http://google.com">external link</a>

    <!-- this will go without asking: -->
    <a href="anotherPage.html" onClick="unhook()">internal link, un-hooked</a>
  </body>
</html>

What it does is you use a variable as a flag.

netadictos
  • 7,602
  • 2
  • 42
  • 69
  • +1 because it is more general and accessible solution. Suppose that I have a script portion that makes page redirect, so before applying the redirect action, I just set `hook = false`. Checkout [**this DEMO**](http://jsbin.com/fadeso/1/) – SaidbakR May 19 '15 at 14:45
  • Based on your solution, I propose that if you use jQuery, use a class like .noConfirm and do something like: $('.noConfirm').click(unhook) – Meowtwo 117 Jul 29 '15 at 03:11
  • @netadictos I recommend you to update your answer to use more modern `.addEventListener()` instead of `onclick` attribute (or `.onbeforeunload = ...`). – Michał Perłakowski Jan 02 '16 at 13:49
  • I recommend you do not use addEventListener since onclick works in all browsers. You can still assign onclick unobtrusively – mplungjan Jan 02 '16 at 14:29
  • @mplungjan Actually, `addEventListener` [works](http://caniuse.com/#feat=addeventlistener) in all browsers. If you think IE <= 8 is a browser too, you can use `attachEvent` method, which has basically the same functionality. – Michał Perłakowski Jan 10 '16 at 12:33
  • Yes - we need to support IE8 and why bother with two event handlers when onclick works in all JS enabled browsers – mplungjan Jan 10 '16 at 13:39
  • @netadictos - Is it possible to write my own javascript code instead of only confirmation box. – Musaddiq Khan May 18 '17 at 10:12
33

Keep your code as is and use jQuery to handle links:

$(function () {
  $("a").click(function {
    window.onbeforeunload = null;
  });
});
intcreator
  • 4,206
  • 4
  • 21
  • 39
M. Utku ALTINKAYA
  • 2,254
  • 23
  • 29
6

You can detect hyperlinks clicks, but you can't determine whether user:

  • Attempted to refresh page.
  • Attempted to close browser tab.
  • Attempted to close browser window.
  • Inputted another URL in the URL bar and hit enter.

All these actions generate beforeunload event on window, without any more exact information about the event.

In order to display confirmation dialog when doing above actions, and not display it when a hyperlink was clicked, follow these steps:

  • Assign beforeunload event listener to window, which returns confirmation text as a string, unless a specific variable (flag) is set to true.
  • Assign click event to document. Check if a element has been clicked (event.target.tagName). If yes, set flag to true.

You should also handle form submissions by assigning a submit event listener to document.

Your code could look like this:

let disableConfirmation = false;
window.addEventListener('beforeunload', event => {
  const confirmationText = 'Are you sure?';
  if (!disableConfirmation) {
    event.returnValue = confirmationText; // Gecko, Trident, Chrome 34+
    return confirmationText;              // Gecko, WebKit, Chrome <34
  } else {
    // Set flag back to false, just in case
    // user stops loading page after clicking a link.
    disableConfirmation = false;
  }
});
document.addEventListener('click', event => {
  if (event.target.tagName.toLowerCase() === 'a') {
    disableConfirmation = true;
  }
});
document.addEventListener('submit', event => {
  disableConfirmation = true;
});
<p><a href="https://stacksnippets.net/">google.com</a></p>
<form action="https://stacksnippets.net/"><button type="submit">Submit</button></form>
<p>Try clicking the link or the submit button. The confirmation dialog won't be displayed.</p>
<p>Try reloading the frame (right click -> "Reload frame" in Chrome). You will see a confirmation dialog.</p>

Note that in some browsers you have to use event.returnValue in beforeunload listener, and in others you use return statement.

See also beforeunload event docs.

Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177
3

I have added an additional code that will to handle further process of if window is closed

let disableConfirmation = false;
window.addEventListener('beforeunload', event => {
  const confirmationText = 'Are you sure?';
  if (!disableConfirmation) {
    event.returnValue = confirmationText; // Gecko, Trident, Chrome 34+
    return confirmationText;              // Gecko, WebKit, Chrome <34
  } else {
    // Set flag back to false, just in case
    // user stops loading page after clicking a link.
    disableConfirmation = false;
  }
});

After Confimation if you want to send any ajax request and you have used jquery

 $(window).on('unload', function() {
   // async: false will make the AJAX synchronous in case you're using jQuery
   axios
     .get('ajax_url')
     .then(response => {});
 });

And if no jquery is used you can use navigator, it require navigator library

navigator.sendBeacon(url, data);

you can download this library from here : https://github.com/miguelmota/Navigator.sendBeacon