Here is the code that works as-is, a classic onBeforeUnLoad event, in the <script type="text/jscript"> tag of my ASP page :
window.onbeforeunload = function (e) {
a = 1;
e = e || window.event;
e.preventDefault = true;
e.cancelBubble = true;
e.returnValue = "do you wish to save?";
}
Now, two issues i'm experiencing when wanting to do something more complex :
I want this to appear only once at all cost :
var a = 0;
window.onbeforeunload = function (e) {
if (a == 0) {
a = 1;
e = e || window.event;
e.preventDefault = true;
e.cancelBubble = true;
e.returnValue = "Wish to save?";
}
}
//Does not work...
I want it to be able to run this other function that works when not combined with the first :
comfirmExit = function(){
if (confirm("Wish to save?") == true) {
document.getElementById('<%= btnEnregistrer.ClientID %>').click();
}
}
// works, but not when combine to the first function
I tried to put this all together... I want the unload event to make my confirm box function run :
window.onbeforeunload = function (e) {
if (a == 0) {
a = 1;
comfirmExit = function(){
if (confirm("Wish to save?") == true) {
document.getElementById('<%= btnEnregistrer.ClientID %>').click();
}
}
}
And now I realize I'm far from being an expert of javascript...
The beforeunload event won't run any obtrusive Javascript for the user (ie alert, confirm etc).
But there is an workaround, the steps should be something like:
Create a boolean flag to check if the user has canceled the exiting of your page (default false).
Create the beforeunload event handler, and check if the game is not
saved.
If it was already saved, then, you do nothing, and let the user go
But if it was not, then you change that boolean flag to true.
You keep an interval dirty-checking if that variable is true, and at anytime it is, you save the game for the user, and then set this variable to false again.
So, doing that, you'll ensure the user always see a message if they're leaving without saving, and if they cancel the exiting, the game will be automatically saved, making the next try pretty smooth.
Take a look at the example below. To test it, open your console, click on Run. Then, try to click on Run again, and you'll see an exiting message. If you confirm it, your console won't show anything. But if you cancel it, then, you'll be kept in the page, then you try to click Run again, and you'll see that no message will appear, but the console will log true.
(function() {
var game = { saved: false };
var canceled = false;
setInterval(function() {
if (canceled) {
game.saved = true;
canceled = false;
}
}, 100);
window.onbeforeunload = function() {
if (!game.saved) {
canceled = true;
return 'Are you sure?';
}
else {
console.log(game.saved);
}
}
})();
Related
In JavaScript, is it possible to distinguish between beforeunload events that were triggered by the user closing a browser tab vs clicking a mailto link?
Basically, I would like to do this:
window.addEventListener("beforeunload", function (e) {
if(browserTabClosed) {
// Do one thing
}
else if (mailtoLinkClicked) {
// Do a different thing
}
}
Found a solution by looking at the event (e below) that gets passed in:
window.addEventListener("beforeunload", function (e) {
// We can use `e.target.activeElement.nodeName`
// to check what triggered the passed-in event.
// - If triggered by closing a browser tab: The value is "BODY"
// - If triggered by clicking a link: The value is "A"
const isLinkClicked = (e.target.activeElement.nodeName === "A");
// If triggered by clicking a link
if (isLinkClicked) {
// Do one thing
}
// If triggered by closing the browser tab
else {
// Do a different thing
}
}
The beforeunload method has an unstable behaviour between browsers, the reason is that browser implementations try to avoid popups and other malicious code runned inside this handler.
There is actually no general (cross-browser) way to detect what triggered the beforeunload event.
Said that, in your case you could just detect a click on the window to discriminate between the two required behaviours:
window.__exit_with_link = false;
window.addEventListener('click', function (e) {
// user clicked a link
var isLink = e.target.tagName.toLowerCase() === 'a';
// check if the link has this page as target:
// if is targeting a popup/iframe/blank page
// the beforeunload on this page
// would not be triggered anyway
var isSelf = !a.target.target || a.target.target.toLowerCase() === '_self';
if (isLink && isSelf) {
window.__exit_with_link = true;
// ensure reset after a little time
setTimeout(function(){ window.__exit_with_link = false; }, 50);
}
else { window.__exit_with_link = false; }
});
window.addEventListener('beforeunload', function (e) {
if (window.__exit_with_link) {
// the user exited the page by clicking a link
}
else {
// the user exited the page for any other reason
}
}
Obviously it is not the proper way, but still working.
At the same way, you could add other handlers to check other reasons the user left the page (eg. keyboard CTRL-R for refresh, etc.)
I have window.onbeforeunload triggering properly. It's displaying a confirmation box to ensure the user knows they are navigating (closing) the window and that any unsaved work will be erased.
I have a unique situation where I don't want this to trigger if a user navigates away from the page by clicking a link, but I can't figure out how to detect if a link has been clicked inside the function to halt the function. This is what I have for code:
window.onbeforeunload = function() {
var message = 'You are leaving the page.';
/* If this is Firefox */
if(/Firefox[\/\s](\d+)/.test(navigator.userAgent) && new Number(RegExp.$1) >= 4) {
if(confirm(message)) {
history.go();
}
else {
window.setTimeout(function() {
window.stop();
}, 1);
}
}
/* Everything else */
else {
return message;
}
}
You're looking for deferred event handling. I'll explain using jQuery, as it is less code:
window._link_was_clicked = false;
window.onbeforeunload = function(event) {
if (window._link_was_clicked) {
return; // abort beforeunload
}
// your event handling
};
jQuery(document).on('click', 'a', function(event) {
window._link_was_clicked = true;
});
a (very) poor man's implementation without jQuery's convenient delegation handling could look like:
document.addEventListener("click", function(event) {
if (this.nodeName.toLowerCase() === 'a') {
window._link_was_clicked = true;
}
}, true);
this allows all links on your page to leave without invoking the beforeunload handler. I'm sure you can figure out how to customize this, should you only want to allow this for a specific set of links (your question wasn't particularly clear on that).
var link_was_clicked = false;
document.addEventListener("click", function(e) {
if (e.target.nodeName.toLowerCase() === 'a') {
link_was_clicked = true;
}
}, true);
window.onbeforeunload = function() {
if(link_was_clicked) {
link_was_clicked = false;
return;
}
//other code here
}
You can differ between a link unload or a reload/user entering a different address unload s by using a timer. This way you know the beforeunload was triggered directly after the link click.
Example using jQuery:
$('a').on('click', function(){
window.last_clicked_time = new Date().getTime();
window.last_clicked = $(this);
});
$(window).bind('beforeunload', function() {
var time_now = new Date().getTime();
var link_clicked = window.last_clicked != undefined;
var within_click_offset = (time_now - window.last_clicked_time) < 100;
if (link_clicked && within_click_offset) {
return 'You clicked a link to '+window.last_clicked[0].href+'!';
} else {
return 'You are leaving or reloading the page!';
}
});
(tested in Chrome)
How can i redirect him if a user clicks on leave a page button on onbeforeunload. Please check my code
function openNewWindow() {
window.open('http://google.com/','_blank');
window.focus();
}
window.onbeforeunload = function(event) {
event = event || window.event;
var confirmClose = 'Are you sure?';
if (event) {
event.returnValue = confirmClose;
if(confirmClose)
{
if(true)
{
openNewWindow();
}
}
return confirmClose;
}
}
Thanks
If the users chooses yes in the onbeforeunload dialog then he will leave the page, you can not prevent this. You can however do some things before the dialog shows, like you are doing in your code, but the dialog it self is only displayed AFTER your function executes, displaying the return value.
Your code seems a bit obscure to, what are you expecting from if(confirmClose), this will always evaluate to true because a non empty string is "truthy" in javascript.
I've been trying to understand even bubbling, and not quite sure I completely follow it. I started reading about it so that I could warn users when they were leaving a page on my website if they had started to enter data into a form (in a similar way to Stack Overflow does!).
The following code seems to work cross-browser:
var entereddata = false;
$(document).ready(function()
{
$('#contactform').bind('keypress',function(e) {
if((e.which > 96 && e.which < 123) || (e.which > 47 && e.which < 58)) {
entereddata = true;
//alert(e.which);
}
});
});
function confirmLeave(e, d)
{
if(!e) e = window.event;//window.event;
if(!d) d = entereddata;
var confirmationMessage = 'It appears you have started to enter information into the contact form, but have not yet submitted it';
if(!d)
{
e.cancelBubble = true;
} else
{
return confirmationMessage;
}
}
window.onbeforeunload=confirmLeave;
However, this also gets called when I click the submit button for the form, which I don't want. I've tried various additions to the code, such as adding:
if($('#submit').click()){
submitted=true;
} else {
submitted=false;
}
and then changing if(!d) to if(!d && submitted==false) to the main code; however, this (and every other combination of trying to get the page to fire only if the submit button isn't clicked) doesn't work, with the warning either still showing when I click the submit button, or no warning being shown when anything is clicked!
This might boil down to the fact I don't understand the event bubbling process - I don't know why I need the e.cancelBubble = true; in the place I have it.
So, my two main problems are:
how do I check if the submit button is clicked, and only show the warning if it isn't clicked
and to understand eventBubbling; for example: if enteredData is true, then I'm not affecting the bubbling process. Should I be? Should I have e.cancelBubble=false if enteredData is false and e.cancelBubble=true if enteredData is true? What effect does setting the value of e.cancelBubble actually have when closing a page?
Am I also correct in thinking I don't need the event e.stopPropagation
at all, because Firefox supports event bubbling?
What about having such code?
$('#submit').click(function() {
entereddata = false;
});
This should be called before the actual form submission i.e. before confirmLeave is running, so lowering the flag should do the trick.
Try removing the onbeforeunload "listener":
$('#submit').click(function() {
window.onbeforeunload=null;
});
I don't think you need to worry about bubbling in this example...
return null if you want the browser to move on without asking the user, or return a string if you want the browser to show an alert asking the user if he wants to move on or not...
function confirmLeave(e) {
e = e || window.event;//window.event;
var confirmationMessage = 'It appears you have started to enter information into the contact form, but have not yet submitted it';
if(entereddata) {
return confirmationMessage;
} else {
return null;
}
}
Bubbling and propagation only applies to event's that should notify it's children or it's parents, and as far as i know window.onbeforeunload is a global event that will not be propagated.
Unrelated to bubbling, but you could bypass detecting whether keys were pressed and check the form data instead:
function hasNonemptyTextInputs() {
var textInputs = $('#contactform :input').filter(':text, textarea');
// Check for any field with a nonempty value
// .is() returns true iff the function returns true on any element
return textInputs.is(function() {
return $(this).val().length > 0;
});
}
I got a function which checks if some input fields are changed:
var somethingchanged = false;
$(".container-box fieldset input").change(function() {
somethingchanged = true;
});
And a function which waits on window.onload and fires this:
window.onbeforeunload = function(e) {
if (somethingchanged) {
var message = "Fields have been edited without saving - continue?";
if (typeof e == "undefined") {
e = window.event;
}
if (e) {
e.returnValue = message;
}
return message;
}
}
But if I edit some of the fields and hit the save button, the event triggers, because there is a post-back and the fields have been edited. Is there anyway around this, so the event does not fire upon clicking the save button?
Thanks
When I do this pattern I have a showDirtyPrompt on the page. Then whenever an action occurs which I don't want to go through the dirty check I just set the variable to false. You can do this on the client side click event of the button.
The nice thing about this is that there might be other cases where you don't want to prompt, the user you might have other buttons which do other post backs for example. This way your dirty check function doesn't have to check several buttons, you flip the responsability around.
<input type="button" onclick="javascript:showDirtyPrompt=false;".../>
function unloadHandler()
{
if (showDirtyPrompt)
{
//have your regular logic run here
}
showDirtyPrompt=true;
}
Yes. Check to see that the button clicked is not the save button. So it could be something like
if ($this.id.not("savebuttonID")) {
trigger stuff
}