Way to know if user clicked Cancel on a Javascript onbeforeunload Dialog?
Asked Answered
M

6

38

I am popping up a dialog box when someone tries to navigate away from a particular page without having saved their work. I use Javascript's onbeforeunload event, works great.

Now I want to run some Javascript code when the user clicks "Cancel" on the dialog that comes up (saying they don't want to navigate away from the page).

Is this possible? I'm using jQuery as well, so is there maybe an event like beforeunloadcancel I can bind to?

UPDATE: The idea is to actually save and direct users to a different webpage if they chose cancel

Marius answered 10/1, 2011 at 19:34 Comment(4)
I don't think it's possible... but I hope I'm wrong.Emotionality
I'm really curious how you block the navigator with a custom dialog. Could you provide the code ?Ebert
@jAndy, look up the onbeforeunload event in Javascript, it does exactly this.Marius
@at: I know about the event, but this will only work the default modal dialog that pops up. Your post sounds like you're creating a custom UI dialog or something within the event handler.Ebert
E
64

You can do it like this:

$(function() {
    $(window).bind('beforeunload', function() {
        setTimeout(function() {
            setTimeout(function() {
                $(document.body).css('background-color', 'red');
            }, 1000);
        },1);
        return 'are you sure';
    });
}); 

The code within the first setTimeout method has a delay of 1ms. This is just to add the function into the UI queue. Since setTimeout runs asynchronously the Javascript interpreter will continue by directly calling the return statement, which in turn triggers the browsers modal dialog. This will block the UI queue and the code from the first setTimeout is not executed, until the modal is closed. If the user pressed cancel, it will trigger another setTimeout which fires in about one second. If the user confirmed with ok, the user will redirect and the second setTimeout is never fired.

example: http://www.jsfiddle.net/NdyGJ/2/

Ebert answered 10/1, 2011 at 20:15 Comment(15)
I went to the link but nothing happened when I closed the window. Using Chrome...Expectorant
Very nice, so it works, not quite for my needs yet though. I don't understand the need for a nested setTimeout, removing the outer setTimeout seems to have the same effect. However, the problem is that the delayed function might get called when trying to "continue" and exit to the page you wanted. Delay it too long and hitting cancel doesn't seem to have an effect and delay it too short and you risk redirecting to the wrong page.Marius
In chrome you can set it to 0ms delay and it works. In IE you have to have a longer timeout or it freaks out.Fletcher
@jAndy. The SetTimeOut is also triggering while user select an Leave on this page option. How can we stop that.Kaiulani
@VIJAY: that's actually the reason for the nested setTimeout. The best thing we can do so far is to workaround the issue. In this example, it gives the browser/connection 1 second to leave the page, if that happens our code won't get executed. If it takes longer than 1 second, the code executes before pageunload. So, its not a very clean solution, but currently the best you can do. Of course, increasing that buffer-timeout is an option.Ebert
As of Jan 2014, this approach doesn't work on chrome.Synthesize
amazing answer, as a comment i just used one timeout and works in chrome, great, been searching for this for hoursManna
@ScottEvernden I just tested it with two recent versions of Chrome and it works (again?) Including version 40.0.2214.94Harass
What if I want it the other way around? For Example: Call a logout method when the user clicked on okay button. And do nothing when the user clicked on cancel button.Alikee
@Alikee You can use var logout = confirm("Sure?");. If Ok logout will have value as true else falseJarid
Works fine with Chrome 47, but doesn't work on Firefox 42. Seems FF immediately executes code inside setTimeout (which was frozen while displaying alert box) if time passed exceeds timeout. So if timeout was 5s, but user was looking at an alert box for 6s, code will be executed, even before 'unload' event (so we can't reset the timer)Rager
This does not work on a slow connection: the second timeout is called regardless confirmation choice and could be executed before the actual unload (on a throttled Chrome).Heckelphone
Doesn't work in Chrome 64. It reeeeeeeally doesn't want you to execute any code. I'm saving onblur. If you click "reload," it saves because the blur is fired. If you just hit enter, it doesn't trigger the onblur and thus does not save.Ube
Actual page unload time depends on the time it takes to begin getting the next page. If the user's PC is slow, or if the next page's server is slow to respond, then this approach will erroneously decide that the user cancelled leaving. It's extemely unreliable.Gryphon
Working fine for me in Chrome 111. Brilliant!Overrate
C
6

I know this question is old now, but in case anyone is still having issues with this, I have found a solution that seems to work for me,

Basically the unload event is fired after the beforeunload event. We can use this to cancel a timeout created in the beforeunload event, modifying jAndy's answer:

$(function() {
    var beforeUnloadTimeout = 0 ;
    $(window).bind('beforeunload', function()  {
        console.log('beforeunload');
        beforeUnloadTimeout = setTimeout(function() {
            console.log('settimeout function');
            $(document.body).css('background-color', 'red');
        },500);
        return 'are you sure';
    });
    $(window).bind('unload', function() {
        console.log('unload');
        if(typeof beforeUnloadTimeout !=='undefined' && beforeUnloadTimeout != 0)
            clearTimeout(beforeUnloadTimeout);
    });
}); 

EDIT: jsfiddle here

Chartres answered 10/9, 2014 at 12:44 Comment(4)
Did that work for you? Because in my case I get the unload like way after the timer function executes... (I tested in Firefox 35)Freelance
Yea this works for me, try increasing the time for your timeout function.Garate
I have tested some more and discovered that if I put about 5 seconds (instead of 0.5) it works as expected. But I think that's too much in case you cancel the dialog... Too bad we do not get any better feedback on that one.Freelance
This is an excellent idea. However, it is affected by latency. At worst case, the Web server is turned off, and the length of the beforeunload timeout has to be equal to the browser's timeout.Frieze
E
2

Not possible. Maybe someone will prove me wrong... What code do you want to run? Do you want to auto-save when they click cancel? That sounds counter-intuitive. If you don't already auto-save, I think it makes little sense to auto-save when they hit "Cancel". Maybe you could highlight the save button in your onbeforeunload handler so the user sees what they need to do before navigating away.

Expectorant answered 10/1, 2011 at 19:45 Comment(1)
The idea is to actually then save and direct them to a different webpage if they chose cancel.Marius
S
2

I didn't think it was possible, but just tried this idea and it works (although it is some what of a hack and may not work the same in all browsers):

window.onbeforeunload = function () {   
  $('body').mousemove(checkunload);
  return "Sure thing"; 
};

function checkunload() {   
  $('body').unbind("mousemove");
  //ADD CODE TO RUN IF CANCEL WAS CLICKED
}
Sovran answered 13/1, 2011 at 23:52 Comment(3)
if you move your mouse after clicking ok to leave site, the "cancel code" is run anyway...Marius
I guess you could add a timeout before binding the mousemove event, that may fix it, although that makes it even more of a hack.Sovran
It takes more than 1 second for the existing window to disappear and if you move your mouse then, it would look like a cancellation. Having a timer has the same drawback as in jAndy's answer which does not work right for me.Freelance
E
0

Another variation The first setTimeout waits for the user to respond to the browser's Leave/Cancel popup. The second setTimeout waits 1 second, and then CancelSelected is only called if the user cancels. Otherwise the page is unloaded and the setTimeout is lost.

window.onbeforeunload  = function(e) {
    e.returnValue = "message to user";
    setTimeout(function () { setTimeout(CancelSelected, 1000); }, 100);
}

function CancelSelected() {
    alert("User selected stay/cancel");
}
Ethnocentrism answered 5/3, 2021 at 14:7 Comment(1)
If i refresh the page and select exit and the new pages takes some time to load, the alert is shown...no goodDreeda
C
-7
window.onbeforeunload  = function() {
    if (confirm('Do you want to navigate away from this page?')) {
        alert('Saving work...(OK clicked)')
    } else {
        alert('Saving work...(canceled clicked)')
        return false
    }
 }

with this code also if user clicks on 'Cancel' in IE8 the default navigation dialog will appear.

Constitute answered 26/11, 2014 at 11:30 Comment(2)
You cannot use confirm() inside a function attached to onbeforeunload.Freelance
@jyoti: It seems like you meant to comment on someone else's answer. To do so, click the add a comment link below a concrete answer. Please remove this answer from the thread as right now it's a duplicate of a wrong answer that will otherwise be downvoted soon.Adenaadenauer

© 2022 - 2024 — McMap. All rights reserved.