Javascript Close Hook for Browser Window
Today I wanted to implement something that would prevent me from accidentally closing the browser window while I was doing stuff in my webapp. I'm no javascript expert, so I checked some newsgroups and found more and more complex solutions the longer the threads were.
Here's what works for me:
<script type="text/javascript">
window.onbeforeunload = function(){
return "Did you save your stuff?"
}
</script>
I have no idea why this behaves as it does, it must be one of those "very interesting ideas" Frank mentioned about javascript.
What it does is this: When the user presses the browser's "x" to close the window, this dialog box is shown:
If the user presses Cancel, the box disappears and the browser window remains open, and if she presses Okay, the browser window closes (who'd have guessed). So far, so good. Unfortunately the message is displayed even if the user clicks on a link or submits a form (to do something within the webapp) .
So how do I fix this? The newsgroups said that I could add a condition to check if I really want to warn the user about closing, like this:
<script type="text/javascript">
var hook=true;
window.onbeforeunload = function() {
if (hook) {
return "Did you save your stuff?"
}
// no return value obviously means no dialog box.
}
function unhook() {
hook=false;
}
</script>
The default is to use the hook, and I can use the
unhook()
function to disable the hook. How does this help? How do I know when I want the hook disabled? Frank knew the solution, and it's really very simple: I want to disable the hook whenever the user clicks on one of my own links or buttons within the webapp. This can be done by adding an
onClick
event to each link or button like this:
<a href="..." onClick="unhook()">Some link within my app</a>
At first it looks a bit cumbersome to change all the links and buttons, but in a webapp, most of the links will be written by some application code anyway so it's not much trouble to change them all at once.
It's a bit strange because what I'm doing here is programming some general behaviour (the hook) and then exclude all the common use-cases (internal links, by calling unhook()) because I can't make javascript react to the few exceptions (browser close button) directly.
The final page looks something like this:
<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://www.google.com">external link</a>
<!-- this will go without asking: -->
<a href="anotherPage.html" onClick="unhook()">internal link, un-hooked</a>
</body>
</html>
Closing or re-loading the window will display the confirm box, too.
Use the following links to check that it works:
Don't leave for Google before you leave a comment.
You shouldn't be able to close this page without warning, either.
There's one small problem left: if you click on the "leave a comment" link, the page will not be re-loaded because it's just a page-internal link, and after that, the hook variable will be false and you won't be asked for confirmation if you click on the google link again. But thankfully I don't have these page-internal links in my webapp...
Addendum: Claus Augusti directed my attention to two official documentation sites about the onbeforeunload event. Thanks you! The documentation in the Mozilla Developer Center explains that one should not just return a string, but should assign a value to the returnValue property of the onbeforeunload event (browser-dependent), like this:
window.onbeforeunload = function (e) {
var e = e || window.event;
if (e) { // For IE and Firefox
e.returnValue = 'Any string';
}
return 'Any string'; // For Safari
};
This is contradictory to the example given in
Microsoft's documentation (returning a string is sufficient), and contrary to my experience with Firefox, but at least it helps to understand why this works at all.