313

Here in stackoverflow, if you started to make changes then you attempt to navigate away from the page, a javascript confirm button shows up and asks: "Are you sure you want to navigate away from this page?" blee blah bloo...

Has anyone implemented this before, how do I track that changes were committed? I believe I could do this myself, I am trying to learn the good practices from you the experts.

I tried the following but still doesn't work:

<html>
<body>
    <p>Close the page to trigger the onunload event.</p>
    <script type="text/javascript">
        var changes = false;        
        window.onbeforeunload = function() {
            if (changes)
            {
                var message = "Are you sure you want to navigate away from this page?\n\nYou have started writing or editing a post.\n\nPress OK to continue or Cancel to stay on the current page.";
                if (confirm(message)) return true;
                else return false;
            }
        }
    </script>

    <input type='text' onchange='changes=true;'> </input>
</body>
</html>

Can anyone post an example?

sshow
  • 8,820
  • 4
  • 51
  • 82
Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632

17 Answers17

452

Update (2017)

Modern browsers now consider displaying a custom message to be a security hazard and it has therefore been removed from all of them. Browsers now only display generic messages. Since we no longer have to worry about setting the message, it is as simple as:

// Enable navigation prompt
window.onbeforeunload = function() {
    return true;
};
// Remove navigation prompt
window.onbeforeunload = null;

Read below for legacy browser support.

Update (2013)

The orginal answer is suitable for IE6-8 and FX1-3.5 (which is what we were targeting back in 2009 when it was written), but is rather out of date now and won't work in most current browsers - I've left it below for reference.

The window.onbeforeunload is not treated consistently by all browsers. It should be a function reference and not a string (as the original answer stated) but that will work in older browsers because the check for most of them appears to be whether anything is assigned to onbeforeunload (including a function that returns null).

You set window.onbeforeunload to a function reference, but in older browsers you have to set the returnValue of the event instead of just returning a string:

var confirmOnPageExit = function (e) 
{
    // If we haven't been passed the event get the window.event
    e = e || window.event;

    var message = 'Any text will block the navigation and display a prompt';

    // For IE6-8 and Firefox prior to version 4
    if (e) 
    {
        e.returnValue = message;
    }

    // For Chrome, Safari, IE8+ and Opera 12+
    return message;
};

You can't have that confirmOnPageExit do the check and return null if you want the user to continue without the message. You still need to remove the event to reliably turn it on and off:

// Turn it on - assign the function that returns the string
window.onbeforeunload = confirmOnPageExit;

// Turn it off - remove the function entirely
window.onbeforeunload = null;

Original answer (worked in 2009)

To turn it on:

window.onbeforeunload = "Are you sure you want to leave?";

To turn it off:

window.onbeforeunload = null;

Bear in mind that this isn't a normal event - you can't bind to it in the standard way.

To check for values? That depends on your validation framework.

In jQuery this could be something like (very basic example):

$('input').change(function() {
    if( $(this).val() != "" )
        window.onbeforeunload = "Are you sure you want to leave?";
});
Mave
  • 2,413
  • 3
  • 28
  • 54
Keith
  • 150,284
  • 78
  • 298
  • 434
  • I have plenty of TBs in my webform, I wanna set a global boolean flag in the page, then with jquery walk thru all the inputs with type=text and set the onchange to change the flag. the use your function evaluating the flag? – Shimmy Weitzhandler Jul 13 '09 at 14:46
  • 4
    That would be something like: $('input:text').change(function() { window.onbeforeunload = $('input:text[value!=""]').length > 0 ? "warning" :null; }); – Keith Jul 13 '09 at 15:07
  • 1
    For a simple check, or you can add more complex validation on each change – Keith Jul 13 '09 at 15:09
  • I edited it to include the anonymous function returning the string, but my edit needs to be peer reviewed. – LocalPCGuy Sep 04 '12 at 22:48
  • NOTE: by default the message will pop up even when **submit button** is clicked, that has to be handled separately. – frnhr Mar 03 '14 at 12:10
  • @frnhr yeah, you need to set `window.onbeforeunload = null;` before any valid action leaves the page too. – Keith Mar 05 '14 at 13:38
  • OK This is a very nice solution, but as frnhr has mentioned, pressing the submit button also triggers this popup. What would be the best way to disable the onbeforeunload action when submit is pressed? I tried this: $('form').submit(function(){window.onbeforeunload = null;}); but it doesn't seem to be working... – Alex Apr 11 '14 at 06:51
  • 1
    it's worth noting that the 'returnValue' method is the only method specified in the standard, so it's not just for IE6-8, it's for all standards-compliant browsers (in this case not including Chrome, Safari, and Opera). – rmcclellan Jun 23 '14 at 19:45
  • @rmcclellan Isn't it funny that IE is the only standards-compliant browser nowadays, even if everyone still thinks it isn't and the others are? /facepalm – JoeBrockhaus Jan 12 '15 at 17:32
  • 3
    To stop the alert on form submission, I used `$("#submit_button").click(function() { window.onbeforeunload = null; });`. I originally used the onclick event of the button, but as well as not being as nice, it also didn't work with IE8. – Andy Beverley Feb 14 '15 at 13:00
  • Minor quibble, but I prefer having the switch built in to the `onbeforeunload` handler (like `if (window.armed){ return "..."; }`). Then code within the page can toggle whether or not the confirmation should be shown, without directly mucking with the `onbeforeunload` property. – aroth Jul 01 '15 at 01:46
  • @aroth it would be better to work that way, but it just doesn't work in a lot of older browsers - they will always show a dialog if anything is assigned. That's my point: you can change the text in the dialog, but you can't change whether it appears from inside onbeforeunload. – Keith Jul 01 '15 at 06:30
  • In Mobile Safari, `onbeforeunload` doesn't exist - need to use the `pagehide` event. – myconode Aug 27 '15 at 00:20
  • How do you replace the `yes/no` texts? – AlikElzin-kilaka Feb 08 '16 at 15:24
  • 1
    @AlikElzin-kilaka you can't. If you want to change the pop-up text then you need to create your own custom popup, but that can't block the `window.onbeforeunload` event. – Keith Feb 08 '16 at 15:28
  • Is there a 2016 version for chrome? It seems like that the returned message won't be displayed, chrome is always displaying the default message. – ROROROOROROR Jul 01 '16 at 01:55
  • As of this writing, [MDN](https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload) lists IE as the only browser that still supports displaying custom text. The other browsers display their own generic message regardless of what you return in your `onbeforeunload` handler. – thewildpendulum Dec 01 '16 at 21:02
  • @Mike, I did already say out of date 4 years ago ;-) I know teams still supporting IE8 - big corps hold on to old software like you wouldn't believe. I've even seen early security-hole riddled builds of IE6 still in use because it was the last browser that allowed some awful hack of the file upload control since deprecated for the massive exploit it allowed. – Keith Mar 28 '17 at 22:17
  • 2017 version copied verbatim doesn't seem to work in a google apps script application - clicking refresh refreshes as usual :/ – user1063287 Oct 11 '17 at 22:03
  • @user1063287 I'm not sure I'd expect it to, it won't work in a frame or certain loading contexts either, mainly because when users click on a link only to get stuck with a wall of dialogs when they try to leave they tend to blame the browser. – Keith Oct 11 '17 at 22:06
  • @Keith - the following works with some issues, I am experiencing: https://stackoverflow.com/questions/46698422/cancelling-page-navigation-with-beforeunload-in-google-apps-script-does-not-canc – user1063287 Oct 11 '17 at 22:20
  • As mentioned in Trevor Karjanis's answer, and also at https://www.geeksforgeeks.org/how-to-detect-browser-or-tab-closing-in-javascript/#:~:text=A%20tab%20or%20window%20closing,the%20tab%20or%20the%20browser., if you'd also like to warn upon closing the browser tab or window, additional include `e.preventDefault();` in your function. – Steve Saporta Sep 30 '22 at 21:00
41

The onbeforeunload Microsoft-ism is the closest thing we have to a standard solution, but be aware that browser support is uneven; e.g. for Opera it only works in version 12 and later (still in beta as of this writing).

Also, for maximum compatibility, you need to do more than simply return a string, as explained on the Mozilla Developer Network.

Example: Define the following two functions for enabling/disabling the navigation prompt (cf. the MDN example):

function enableBeforeUnload() {
    window.onbeforeunload = function (e) {
        return "Discard changes?";
    };
}
function disableBeforeUnload() {
    window.onbeforeunload = null;
}

Then define a form like this:

<form method="POST" action="" onsubmit="disableBeforeUnload();">
    <textarea name="text"
              onchange="enableBeforeUnload();"
              onkeyup="enableBeforeUnload();">
    </textarea>
    <button type="submit">Save</button>
</form>

This way, the user will only be warned about navigating away if he has changed the text area, and will not be prompted when he's actually submitting the form.

Rob W
  • 341,306
  • 83
  • 791
  • 678
Søren Løvborg
  • 8,354
  • 2
  • 47
  • 40
20

To make this work in Chrome and Safari, you would have to do it like this

window.onbeforeunload = function(e) {
    return "Sure you want to leave?";
};

Reference: https://developer.mozilla.org/en/DOM/window.onbeforeunload

Rob W
  • 341,306
  • 83
  • 791
  • 678
sshow
  • 8,820
  • 4
  • 51
  • 82
18

With JQuery this stuff is pretty easy to do. Since you can bind to sets.

Its NOT enough to do the onbeforeunload, you want to only trigger the navigate away if someone started editing stuff.

Alvaro Montoro
  • 28,081
  • 7
  • 57
  • 86
Sam Saffron
  • 128,308
  • 78
  • 326
  • 506
  • 2
    Can't seem to hit @jonstjohn 's blog posts. Maybe he'll be a pal and point us in the right direction? :D – FLGMwt Jun 02 '14 at 20:19
  • 16
    => 500 Internal error. That's why links are deprecated on SO. Downvoted until fixed. – Loïc Sep 19 '14 at 10:15
  • This webpage is not available – Mateusz May 11 '15 at 09:21
  • 3
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. – bwest Jul 14 '15 at 20:13
  • 2009 @bwest feel free to edit this, I wrote this answer a lifetime ago. – Sam Saffron Jul 15 '15 at 06:34
  • 2
    The [original link from Jon St John](http://jonstjohn.com/node/23) was broken, so I updated it to the [Wayback Machine](http://web.archive.org/web/20130730025134/http://jonstjohn.com/node/23) version of it. The content of the link can be found copied in many other sites, but I guess it was better to "preserve" the one that Sam added – Alvaro Montoro Jul 15 '15 at 18:36
14

jquerys 'beforeunload' worked great for me

$(window).bind('beforeunload', function(){
    if( $('input').val() !== '' ){
        return "It looks like you have input you haven't submitted."
    }
});
Devon Peticolas
  • 430
  • 5
  • 9
  • Bind has been deprecated and a newer version of code similar to this can be seen in this answer: http://stackoverflow.com/a/1889450/908677 – Elijah Lofgren Jan 22 '16 at 21:44
11

This is an easy way to present the message if any data is input into the form, and not to show the message if the form is submitted:

$(function () {
    $("input, textarea, select").on("input change", function() {
        window.onbeforeunload = window.onbeforeunload || function (e) {
            return "You have unsaved changes.  Do you want to leave this page and lose your changes?";
        };
    });
    $("form").on("submit", function() {
        window.onbeforeunload = null;
    });
})
Carl G
  • 17,394
  • 14
  • 91
  • 115
8

To expand on Keith's already amazing answer:

Custom warning messages

To allow custom warning messages, you can wrap it in a function like this:

function preventNavigation(message) {
    var confirmOnPageExit = function (e) {
        // If we haven't been passed the event get the window.event
        e = e || window.event;

        // For IE6-8 and Firefox prior to version 4
        if (e)
        {
            e.returnValue = message;
        }

        // For Chrome, Safari, IE8+ and Opera 12+
        return message;
    };
    window.onbeforeunload = confirmOnPageExit;
}

Then just call that function with your custom message:

preventNavigation("Baby, please don't go!!!");

Enabling navigation again

To re-enable navigation, all you need to do is set window.onbeforeunload to null. Here it is, wrapped in a neat little function that can be called anywhere:

function enableNavigation() {
    window.onbeforeunload = null;
}

Using jQuery to bind this to form elements

If using jQuery, this can easily be bound to all of the elements of a form like this:

$("#yourForm :input").change(function() {
    preventNavigation("You have not saved the form. Any \
        changes will be lost if you leave this page.");
});

Then to allow the form to be submitted:

$("#yourForm").on("submit", function(event) {
    enableNavigation();
});

Dynamically-modified forms:

preventNavigation() and enableNavigation() can be bound to any other functions as needed, such as dynamically modifying a form, or clicking on a button that sends an AJAX request. I did this by adding a hidden input element to the form:

<input id="dummy_input" type="hidden" />

Then any time I want to prevent the user from navigating away, I trigger the change on that input to make sure that preventNavigation() gets executed:

function somethingThatModifiesAFormDynamically() {

    // Do something that modifies a form

    // ...
    $("#dummy_input").trigger("change");
    // ...
}
Community
  • 1
  • 1
Mike
  • 23,542
  • 14
  • 76
  • 87
5

The standard states that prompting can be controlled by canceling the beforeunload event or setting the return value to a non-null value. It also states that authors should use Event.preventDefault() instead of returnValue, and the message shown to the user is not customizable.

As of 69.0.3497.92, Chrome has not met the standard. However, there is a bug report filed, and a review is in progress. Chrome requires returnValue to be set by reference to the event object, not the value returned by the handler.

It is the author's responsibility to track whether changes have been made; it can be done with a variable or by ensuring the event is only handled when necessary.

window.addEventListener('beforeunload', function (e) {
    // Cancel the event as stated by the standard.
    e.preventDefault();
    // Chrome requires returnValue to be set.
    e.returnValue = '';
});
    
window.location = 'about:blank';
Trevor Karjanis
  • 1,485
  • 14
  • 25
3

When the user starts making changes to the form, a boolean flag will be set. If the user then tries to navigate away from the page, you check that flag in the window.onunload event. If the flag is set, you show the message by returning it as a string. Returning the message as a string will popup a confirmation dialog containing your message.

If you are using ajax to commit the changes, you can set the flag to false after the changes have been committed (i.e. in the ajax success event).

Kirtan
  • 21,295
  • 6
  • 46
  • 61
3

Here try this it works 100%

<html>
<body>
<script>
var warning = true;
window.onbeforeunload = function() {  
  if (warning) {  
    return "You have made changes on this page that you have not yet confirmed. If you navigate away from this page you will lose your unsaved changes";  
    }  
}

$('form').submit(function() {
   window.onbeforeunload = null;
});
</script>
</body>
</html>
Werner
  • 14,324
  • 7
  • 55
  • 77
Braydon
  • 33
  • 5
1

You can add an onchange event on the textarea (or any other fields) that set a variable in JS. When the user attempts to close the page (window.onunload) you check the value of that variable and show the alert accordingly.

Makram Saleh
  • 8,613
  • 4
  • 27
  • 44
  • 1
    You can't do this - `alert` and `confirm` are blocked during `window.onbeforeunload` and `window.onunload` (at the very least in the version of Chrome on my PC, but probably also in every browser ever to support those handlers). – Mark Amery Jul 17 '13 at 19:56
1

Based on all the answers on this thread, I wrote the following code and it worked for me.

If you have only some input/textarea tags which requires an onunload event to be checked, you can assign HTML5 data-attributes as data-onunload="true"

for eg.

<input type="text" data-onunload="true" />
<textarea data-onunload="true"></textarea>

and the Javascript (jQuery) can look like this :

$(document).ready(function(){
    window.onbeforeunload = function(e) {
        var returnFlag = false;
        $('textarea, input').each(function(){
            if($(this).attr('data-onunload') == 'true' && $(this).val() != '')
                returnFlag = true;
        });

        if(returnFlag)
            return "Sure you want to leave?";   
    };
});
Sagar Gala
  • 944
  • 10
  • 10
  • 2
    See also *"For some reasons, Webkit-based browsers don't follow the spec for the dialog box"* in MDN's [beforeunload documentation](https://developer.mozilla.org/en-US/docs/Mozilla_event_reference/beforeunload). – Arjan Feb 26 '13 at 19:17
1

here is my html

<!DOCTYPE HMTL>
<meta charset="UTF-8">
<html>
<head>
<title>Home</title>
<script type="text/javascript" src="script.js"></script>
</head>

 <body onload="myFunction()">
    <h1 id="belong">
        Welcome To My Home
    </h1>
    <p>
        <a id="replaceME" onclick="myFunction2(event)" href="https://www.ccis.edu">I am a student at Columbia College of Missouri.</a>
    </p>
</body>

And so this is how I did something similar in javaScript

var myGlobalNameHolder ="";

function myFunction(){
var myString = prompt("Enter a name", "Name Goes Here");
    myGlobalNameHolder = myString;
    if (myString != null) {
        document.getElementById("replaceME").innerHTML =
        "Hello " + myString + ". Welcome to my site";

        document.getElementById("belong").innerHTML =
        "A place you belong";
    }   
}

// create a function to pass our event too
function myFunction2(event) {   
// variable to make our event short and sweet
var x=window.onbeforeunload;
// logic to make the confirm and alert boxes
if (confirm("Are you sure you want to leave my page?") == true) {
    x = alert("Thank you " + myGlobalNameHolder + " for visiting!");
}
}
1

From the WebAPIs->WindowEventHandler->onbeforeunload, it recommends use window.addEventListener() and the beforeunload event, instead of onbeforeunload.

Syntax example

window.addEventListener("beforeunload", function(event) { ... });
window.onbeforeunload = function(event) { ... };

Note: The HTML specification states that authors should use the Event.preventDefault() method instead of using Event.returnValue to prompt the user.

So, in terms of your case, the code should look like this:

//javascript
window..addEventListener("beforeunload", function(event) { 
    //your code

    // If you prevent default behaviour in Mozilla Firefox prompt will always be shown
    e.preventDefault();

    // Chrome requires returnValue to be set
    e.returnValue = '';
})
Kaiwen Luo
  • 370
  • 4
  • 10
0

What you want to use is the onunload event in JavaScript.

Here is an example: http://www.w3schools.com/jsref/event_onunload.asp

z-boss
  • 17,111
  • 12
  • 49
  • 81
waqasahmed
  • 3,555
  • 6
  • 32
  • 52
0

It can be easily done by setting a ChangeFlag to true, on onChange event of TextArea. Use javascript to show confirm dialog box based on the ChangeFlag value. Discard the form and navigate to requested page if confirm returns true, else do-nothing.

simplyharsh
  • 35,488
  • 12
  • 65
  • 73
-1

There is an "onunload" parameter for the body tag you can call javascript functions from there. If it returns false it prevents navigating away.

stribika
  • 3,146
  • 2
  • 23
  • 21