I came across a lot of similar questions on stack overflow, but the issue is that most of them are old (as in answered near about 3 to 4 years ago).
PROBLEM
I want to execute a function when the tab is closed (I want to use vanilla java-script) . I've tried doing the following:
// No.1 -> THROWS AN ERROR *Blocked alert('hello') before onunload*
window.onunload = function() {
alert('hello');
}
// No.2 -> THROWS AN ERROR *Blocked alert('hello') before onunload*
window.onbeforeunload = function(){
alert('hello')
};
Way no.3 shown below works as it throws a dialog before leaving or reloading, but the issue is that it runs a function when we click "X" and try to close the tab but when the dialog appears which has two buttons leave and cancel.
window.addEventListener('beforeunload', (event) => {
event.preventDefault();
event.returnValue = '';
bye();
});
function bye() {
console.log('leaving');
}
The way presented above runs the function when we click on "X" but logically the function should run after we click on leave. Refer to the Screenshot below :
I need the function to execute after we click on leave or is there any other way to achieve this ?
PS: I am running vue-js but need plain JS solution
If I understand what you want to do, a combination of beforeunload and unload event listeners may do the trick.
Note that there are many restrictions on what you can do inside these listeners; see the MDN links above for details. For example, as you found, you can not use alert() inside them. But you can write to localStorage, for example.
Here is an example page that uses localStorage to save the time the page was last closed and display it when the page is loaded again. See if this is close to what you want:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Remember Page Close Time</title>
</head>
<body>
<div>
This page was last closed on:
<span id="closetime">Never before</span>
</div>
<script>
window.addEventListener( 'beforeunload', function( event ) {
event.preventDefault();
event.returnValue = '';
});
window.addEventListener( 'unload', function( event ) {
localStorage.setItem( 'closetime', '' + new Date );
});
const closetime = localStorage.getItem( 'closetime' );
if( closetime ) {
document.getElementById('closetime').innerText = closetime;
}
</script>
</body>
</html>
I am developing an online testing app and it is required that during the test, users cannot be allowed to refresh page neither go back until the test is ended. I have successfully been able to disable refresh action in jquery through all means possible (to the best of my knowledge) using the following code:
$(window).bind({
beforeunload: function(ev) {
ev.preventDefault();
},
unload: function(ev) {
ev.preventDefault();
}
});
But I have been having troubles disabling the back action on all browsers, the best solution I got on SO conflicts with the code I have above, it is given below:
window.onload = function () {
if (typeof history.pushState === "function") {
history.pushState("jibberish", null, null);
//alert("Reloaded");
window.onpopstate = function () {
history.pushState('newjibberish', null, null);
// Handle the back (or forward) buttons here
// Will NOT handle refresh, use onbeforeunload forthis.
};
}
else {
var ignoreHashChange = true;
window.onhashchange = function () {
if (!ignoreHashChange) {
ignoreHashChange = true;
window.location.hash = Math.random();
// Detect and redirect change here
// Works in older FF and IE9
// * it does mess with your hash symbol (anchor?) pound sign
// delimiter on the end of the URL
}
else {
ignoreHashChange = false;
}
};
}
}
The solution above suits my purpose in disabling the back button but conflicts with the page refresh prevention handler above.
I am out of ideas on what to do and I have also searched a long time for a solution to this but found none yet. Any help would be greatly appreciated, even if it takes a totally different approach to solving the problem, I wouldn't mind at all.
Thanks everyone
UPDATE
I never realized that doing things this way breaks a lot of ethical rules, anyway, I've thought about it and figured out something else to do when if the page is refreshed or back button pressed (either using keyboard or the browser controls). I want to redirect to a url which will end the current exam session. I believe that's possible, hence I think the solution I seek is to get the best way to achieve this. Redirecting to another url if back button or refresh button is pressed (both using the browser controls and the keyboard).
I have tried many options but none worked except this-
//Diable Browser back in all Browsers
if (history.pushState != undefined) {
history.pushState(null, null, location.href);
}
history.back();
history.forward();
window.onpopstate = function () {
history.go(1);
};
With regards to the update I posted in my question, I have been able to solve my problem. Here's what I did (just modifying my existing code a little and removing the window.onload listener I had initially):
$(window).bind({
beforeunload: function(ev) {
window.location.replace("my_url_goes_in_here");
},
unload: function(ev) {
window.location.replace("my_url_goes_in_here");
}
});
This construct works for both page refresh and back actions done in anyway (either using keyboard or browser controls for the any of them).
However, I've not yet tested in any other browser other than firefox 47.0, but I'm glad it's working for now all the same.
Thanks for all your comments, they were extremely helpful
Using javascript if you have two pages page1 and page2 and (page1 redirect to page2) and you want to restrict the user from getting back to page1, just put this code at page1.
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
$(document).ready(function () {
function disableBack() {
window.history.forward()
}
window.onload = disableBack();
window.onpageshow = function (evt) {
if (evt.persisted)
disableBack()
}
});
</script>
I am working on an application where I want user to continue without clicking back button. I want to prevent them to go back and perform same task again and if they click back button then display a popup message with bootstrap modal.
Here is my code snippet.
function showPopup(url, valid_device) {
if (window.history && window.history.pushState) {
$(window).on('popstate', function() {
$('#bckBtnModal').modal('show');
});
$(window).on('DOMContentLoaded', function() {
$('#bckBtnModal').modal('show');
});
}
}
function moveForward(url){
window.history.pushState( 'forward', null, url );
history.forward()
}
function checkState(url, valid_device){
if (window.history && window.history.pushState) {
window.history.pushState({},'forward', null, url);
$(window).on('popstate', function() {
$('#bckBtnModal').modal('show');
});
$(window).on('DOMContentLoaded', function() {
if(valid_device && show_on_dom_event && push_state_enable){
$('#bckBtnModal').modal('show');
}
});
}
}
I have used above function like given below:
window.onpageshow = BackBtnHandler.showPopup('/reservations/guest_party_details', '<%= valid_device?%>')
window.onnavigate = BackBtnHandler.moveForward('/reservations/guest_party_details');
But it is not global solution, I found that on OSx chromium browser when page loaded two functions called because it fires two event popstate, DOMContentLoaded while the other most of the browsers either calls popstate or DOMContentLoaded.
I have also tried history.js but didn't get any useful from it.
Anyone have any global solution which works for all major browsers and for all major Operating systems?
I've been experiencing an odd problem with IE10 when redirecting the page on an 'oninput' event (with no equivalent issue when using Chrome). I've produced the most pared-down version of the code that still exhibits the problem, as follows:
<html>
<head>
<script type="text/javascript">
function onChangeInputText()
{
window.location.href = "oninput_problem.html"; // Back to this page.
}
</script>
</head>
<body>
<input type="text"
oninput="onChangeInputText()"
value="£"
/>
</body>
</html>
On my Windows 7 PC using IE10, this code when browsed to (either by double clicking or via Apache) repeatedly redirects as if the act of initialising the value of the input text box itself is generating an immediate 'oninput' event. However, when I change the initial input text box value from the '£' symbol to a letter 'A', the repeated redirection doesn't occur.
I first noticed this problem as part of a project I'm working on. In that case, the user's input should cause a delayed page refresh, which began repeatedly redirecting when I entered a '£' symbol. As I say, the above code is the most pared-down version I produced in trying to track what was causing the issue.
Does anyone else experience this using IE10? If so, can anyone explain why IE10 is behaving this way?
I've found the following that appears to indicate that this may be a bug in IE10:
social.msdn.microsoft.com: Event oninput triggered on page load
Also, there's a follow-up bug report (within the page linked to above):
connect.microsoft.com: onInput event fires on loading the page when input #value is non-ASCII
EDITED TO ADD: At the bottom of the page pointed to by the second link, there's what would seem to be an unhelpful reply from Microsoft stating that they are unable to reproduce the bug described, so it may be a while before the issue is fixed...
There's anoter bug report which is still open :
http://connect.microsoft.com/IE/feedback/de...
For anyone who might encounter this, you can use this "class" as an alternative to the onInput event.
const getFieldWatcherInstance = (function(watchedElement, onElementValueChange){
let intervalReference = null;
let lastValue = null;
if(!watchedElement instanceof Element) return new Error('watchedElement is not an HTML Element');
if(typeof onElementValueChange !== 'function') return new Error('onElementValueChange is not a function');
return {
toggleFieldWatching : function(){
if(intervalReference){
clearInterval(intervalReference);
intervalReference = null;
}
else{
intervalReference = setInterval(function(){
const currentValue = watchedElement.value;
if(lastValue !== currentValue){
onElementValueChange(currentValue);
lastValue = currentValue;
}
}, 100);
}
}
};
});
Set it up like this:
const myInputChangeWatcher = getFieldWatcherInstance(<**insert real element reference here**>, function(newValue){
console.log('The new value is: ' + newValue);
});
call myInputChangeWatcher.toggleFieldWatching() in the onfocus and onblur events of the input
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?
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?";
});
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.
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
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.
jquerys 'beforeunload' worked great for me
$(window).bind('beforeunload', function(){
if( $('input').val() !== '' ){
return "It looks like you have input you haven't submitted."
}
});
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;
});
})
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");
// ...
}
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';
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).
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>
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.
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?";
};
});
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!");
}
}
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 = '';
})
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.
What you want to use is the onunload event in JavaScript.
Here is an example: http://www.w3schools.com/jsref/event_onunload.asp
There is an "onunload" parameter for the body tag you can call javascript functions from there. If it returns false it prevents navigating away.