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>
Related
I'm trying to handle window.onpopstate event in my single page app and in Google Chrome and Opera it doesn't work.
This is my simple html page
<html>
<head>
<meta charset="utf-8" />
<script>
window.onpopstate = function(e) {
alert('onpopstate');
}
setTimeout(function () {
history.pushState(1, 'Hello John', '/hello/john');
}, 2000);
setTimeout(function () {
history.pushState(2, 'Hello Emily', '/hello/emily');
}, 3000);
</script>
</head>
<body></body>
</html>
When I hit browser's back button I expect to see alert with onpopstate text to be shown. In Safari, Firefox, Vivaldi it works as expected. In Chrome and Opera it never called, it is just going to previous page by reloading it which is bad scenario for my SPA.
What is more weird is that I found some trick to make it work:
go to dev tools, console tab
simply execute console.log(history) or even console.log(window)
and it magically starts working! But if I do the same in script on the page with or without timeout this trick doesn't work at all. So the only way to make onpopstate work which I found is to manually go to console and execute console.log(history).
Maybe I'm missing something? Any help would be appreciated.
My environment:
macOS 11.0.1 (20B29)
Chrome 87.0.4280.67 (Official Build) (x86_64)
Opera 72.0.3815.378
Posted Chromium bug
SOLUTION:
Ok, this is not a bug, it is a feature! It is kinda interact first feature of Chromium. If user interact first somehow with a page then everything gonna work, otherwise back button will go back with reloading.
So e.g. just add some button into body and click on it first, then try to click back in browser.
<body>
<button onclick="alert('hello');">alert</button>
</body>
To be able to run some javascript like moving on history or play sounds or pop up windows the user first hast to interact (click) on the web site.
you can find more info here:
WebUpdates 2017
There's note I found on MDN. It says:
Note: Calling history.pushState() or history.replaceState() won't
trigger a popstate event. The popstate event is only triggered by
performing a browser action, such as clicking on the back button (or
calling history.back() in JavaScript), when navigating between two
history entries for the same document.
You can learn more here.
And I suggest you to register your event handler to the addEventListener() instead of registering it to onpopstate property of WindowEventHandlers.
Example:
<html>
<head>
<meta charset="utf-8" />
<script>
// ref: https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event
window.addEventListener('popstate', function(e) {
alert('onpopstate');
}
setTimeout(function () {
history.pushState(1, 'Hello John', '/hello/john');
}, 2000);
setTimeout(function () {
history.pushState(2, 'Hello Emily', '/hello/emily');
}, 3000);
</script>
</head>
<body></body>
</html>
Use an Object for the state. From MDN
The state object is a JavaScript object which is associated with the
new history entry created by pushState(). Whenever the user navigates
to the new state, a popstate event is fired, and the state property of
the event contains a copy of the history entry's state object.
const log = Logger();
// create 3 'history pages'
history.pushState({page: 1, greet: "Hello John"}, '', "#John");
history.pushState({page: 2, greet: "Hello Emily"}, '', "#Emily");
history.pushState({page: 3, greet: "Hello James"}, '', "#James");
log(`current history state: ${JSON.stringify(history.state)}`);
// on popstate log the history state if applicable
window.addEventListener("popstate", () =>
history && history.state && log(`${history.state.greet || ""} #page ${
history.state.page} (location: ${location.hash})`)
);
// listener for the buttons
document.addEventListener("click", evt => {
if (evt.target.nodeName === "BUTTON") {
return evt.target.id === "back" ? history.back() : history.forward();
}
});
// helper function for logging in the document
function Logger() {
let logEl;
if (typeof window === "object") {
logEl = document.querySelector("#log") || (() => {
document.body.append(
Object.assign(document.createElement('pre'),
{id: "log"}));
return document.querySelector("#log");
})();
return (...logLines) =>
logLines.forEach(s => logEl.textContent += `${s}\n`);
} else {
return (...logLines) =>
logLines.forEach(ll => console.log(`* `, ll));
}
}
<button id="back"><< 1 back</button>
<button id="forward">1 forward >></button>
I want to open 10 webpages one after another, in the same browser window and with some specific delay.
e.g. I want
open "www.Anywebsite.com"
Delay 5 seconds
In the same page open a new "www.Anywebsite.com"
I am trying to do something like this
<!DOCTYPE html>
<html>
<body>
<script>
var myVar=setInterval(function(){myTimer()},1000);
var condOpen = 0;
function myTimer()
{
if (condOpen == 0)
{
window.open("http://www.tut.fi","_self");
condOpen = condOpen + 1;
}
else if(condOpen == 1)
{
window.open("www.w3schools.com","_self");
}
}
</script>
</body>
</html>
The problem is it opens only the first page, and as I read about "setInterval", it must execute the function specified after some delay. Please help me in this, I have no prior experience with JavaScript but this is needed for a particular task I am doing.
Your code is failing because when you call window.open() with the _self parameter, it's just like doing window.location = "http://www.example.com/";. This replaces your page with the new page you're loading. All JavaScript on your page is killed, including any timers.
You can do something like what you're trying to do here, but you would need to use a different target window name in the window.open() call. You can make up any arbitrary name here; just don't begin the name with _ to avoid the special names like _self.
Unfortunately, you will run afoul of popup blockers if you do this. In order to get past the popup blockers, what you need to do is have the first window.open() be triggered directly by a user action, e.g. by clicking a button. After that you can use the timer to change URLs in the window you've opened.
Also you will get tired of writing if statements when you want to add more URLs to your list. You can use an array of URLs to simplify the code.
And finally, it would be a really good idea to indent your JavaScript code to show its structure. Putting it all against the left margin makes it hard to follow.
Putting those together:
<!DOCTYPE html>
<html>
<head>
<title>Window Loop Test</title>
</head>
<body>
<button onclick="start()">Start</button>
<script>
var targets = [
'http://www.stackoverflow.com/',
'https://developer.mozilla.org/en-US/',
'http://www.w3fools.com/'
];
var iTarget;
function nextTarget(){
window.open( targets[iTarget], 'target' );
if( ++iTarget >= targets.length ) {
iTarget = 0;
}
}
function start() {
iTarget = 0;
nextTarget();
setInterval( nextTarget, 5000 );
}
</script>
</body>
</html>
And here is a fiddle to test.
I've found a plugin called screenfull.js and I'm wondering if it's possible to automatically open the page in fullscreen without clicking on a button.
This is an example of code for making the page fullscreen :
document.getElementById('#button').addEventListener('click', function() {
if ( screenfull ) {
screenfull.request();
} else {
// Ignore or do something else
}
});
Using their demo, you could just run the request on window load:
e.g.
window.onload = function() {
screenfull.request( $('#container')[0] );
};
[edit]
You could also run this with jQuery document ready...
E.g.
$(document).ready(function() {
screenfull.request( $('#container')[0] );
});
No, that is not possible. The requestFullScrenn() must be triggered by a direct user action (like a click) for security considerations. It's just the same as with popups.
Read https://wiki.mozilla.org/Security/Reviews/Firefox10/CodeEditor/FullScreenAPI and maybe https://wiki.mozilla.org/Gecko:FullScreenAPI for reference.
I use a trick...
I listen for any click on the body to activate.
Eg:
$('body').on('click', '*', function() {
screenfull.request();
});
N.B.: It does not track buttons (e.t.c) that already have event handlers...
I am opening a child window for Facebook sharing this way:
window.open(sharingUrl,'','toolbar=0,status=0,width=626,height=436');
The window is automatically closed when a user clicks share or close...
Is there a way to add a listener to these events?
If you store a reference to the child window when you call window.open(), then you can poll using setInterval() to see whether the window is still open using the window.closed property. The example below checks twice per second.
var child = window.open('http://google.com','','toolbar=0,status=0,width=626,height=436');
var timer = setInterval(checkChild, 500);
function checkChild() {
if (child.closed) {
alert("Child window closed");
clearInterval(timer);
}
}
Note to others: If you are ever in a situation where you have control over the html in the child window, you could make use of the onbeforeunload event and alert the parent window.
For future references, I'd like to share another solution that doesn't require setInterval :
var child = window.open('http://google.com','','toolbar=0,status=0,width=626,height=436');
child.onunload = function(){ console.log('Child window closed'); };
This will work fine
<html>
<head>
<title>Detecting browser close in IE</title>
<script type="text/javascript">
window.onbeforeunload = function(){ myUnloadEvent(); }
function myUnloadEvent() {
alert ('You can have Ur Logic Here ,');
}
</script>
</head>
</script>
</head>
<body >
<h1>Close the Window now</h1>
</body>
</html>
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.