onbeforeunload event is too enthusiastic in IE9

teedyay picture teedyay · Aug 31, 2011 · Viewed 12.5k times · Source

Here's some sample test html:

<!DOCTYPE html>
<html>
  <body>
    <a href="javascript:alert('Not going anywhere!');">Go nowhere 1</a>
    <a href="javascript:void(0);" onclick="alert('Not going anywhere!');">Go nowhere 2</a>
    <a href="http://www.google.com">Go somewhere</a>
    <script type="text/javascript">
      window.onbeforeunload = function() { return "Really leave?"; };
    </script>
  </body>
</html>

This is available as a working page here: timjeanes.com/ie9_onbeforeunload.htm

In Firefox, Chrome and Safari, I get the behaviour I want. That is, clicking either of the first two links shows an alert dialog; clicking the third link (or otherwise navigating away) shows the "Are you sure you want to leave this page?" message.

However, in IE9, the "Are you sure you want to leave this page?" message also shows when you click either of the first two links, even though no navigation is taking place - we're just running some javascript.

Is there something I'm doing wrong? Or is there a nice workaround for IE?

One option would be to use href="#" and put my javascript in the onclick. I'm not keen on that as it takes the user to the top of the page, and my real-life page is quite tall.

I've not tested in other versions of IE.

Answer

gilly3 picture gilly3 · Aug 31, 2011

That's a pretty unfortunate bug. It seems you'll have to work around it, and using the hash link method is probably the best way. To avoid taking the user to the top of the page, cancel the event using event.preventDefault() and event.returnValue = false.

function myClickHandler(e) {
    if (e.preventDefault)
        e.preventDefault();
    e.returnValue = false;
    alert("Not going anywhere!");
}

Call it like this:

<a href="#" onclick="myClickHandler(event)">Go nowhere 1</a>

Edit: You could cancel the event for all the hash-links on your page like this:

var links = document.links;
for (var i = 0; i < links.length; i++) {
    var link = links[i];
    if (link.href == "#") {
        if (link.addEventListener) {
            link.addEventListener("click", cancelEvent, false);
        }
        else if (link.attachEvent) {
            link.attachEvent("onclick", cancelEvent);
        }
    }
}
function cancelEvent(e) {
    e = e || window.event;
    if (e.preventDefault)
        e.preventDefault();
    e.returnValue = false;
}

Or with jQuery using just one line of code:

$("a[href='#']").click(function (e) { e.preventDefault(); });