Popup when leaving website
On my current project, we had a requirement to pop up a message to the user when they leave our site (e.g., close the browser window). We discovered a number of sites talking about a window.close event, but it is not supported in modern browsers (IE 6, Firefox 2, Safari 2). The closest event is an unload event which gets fired when the page is unloaded.
We tried using this event in a javascript file that is included on every page:
window.onunload = popup;
function popup() {
alert('I see you are leaving the site');
}
Unfortunately, an unload event is fired when the user leaves the page for any reason (such as clicking on a link). We did not want to show the popup if the user clicked on a link which stayed on the site.
Our next idea was to add an onclick to every link which would turn off the popup. Then, if the user clicks a link, nothing happens. If they leave the site another way, they get the popup.
Toby Tripp had the great idea to add these onclicks dynamically in javascript. We use prototype, so the code looks like:
staying_in_site = false;
$$('a').each(function(link) {
link.observe('click', function() {staying_in_site = true;});
});
window.onunload = popup;
function popup() {
if(staying_in_site) {
return;
}
alert('I see you are leaving the site');
}
This code creates a variable which determines whether or not to show the popup. Then, we find every link with $$(‘a’). This is a CSS selector which selects all of the a elements. We iterate over these links and add a listener which sets the staying_in_site flag to true. Now, our popup code checks this flag and knows whether the user is staying on the site.
It is important to include this javascript at the bottom of the file (and not in the head). The javascript must be executed after the page is written or the links will not exist yet.
This solution is not perfect, but it accomplishes most of what we need.
Update (1/31/08): Simon Stewart suggested a cleaner method in the comments:
staying_in_site = false;
Event.observe(document.body, 'click', function(event) {
if (Event.element(event).tagName == 'A') {
staying_in_site = true;
}
});
window.onunload = popup;
function popup() {
if(staying_in_site) {
return;
}
alert('I see you are leaving the site');
}
Instead of attaching an event listener to every link, we can attach a click listener to the whole body. Now, any click will call our function, which checks to see if you clicked on a link. Since we are not iterating over existing links, this javascript does not have to be below the links in the page.
Comments
-
How does your solutions handle forms? Do you have to register them in the same way?
-
Why not just attach a click listener to the body tag and check the original target to see if it's a link? That'll run faster, and means that you're not relying on the location of the script in the page.
-
With Prototype, it's easy to write the link behavior within the head using Event.oberve ( window, 'unload', ... ). As Simon mentions (sorry, I couldn't write "As Simon says" :-), then you're not reliant on script position.
-
Simon, that's a great idea. We just switched our implementation to what you suggested. Andy, Simon's solution catches submit buttons as well.
-
if you're responding to clicks on the document body, wouldn't you need to add staying_in_site = false; inside the conditional in case the user clicks on some random bit of background on the page, so that afterwards, when the user really leaves the page (not via a link) the popup function will behave as desired?
-
Conan, you are correct. I fixed the code sample.
-
Sorry ... have not much experience in js but I don't understand how the code handles the submit.
-
Nick, The click listener will catch all clicks, including submit buttons (input tags). So you can modify the line "Event.element(event).tagName == 'A'" to something that checks if the element is an input button.
-
When I moved the above code in to my site, I got the following error: element has no properties (prototype.js line 2244). Any thoughts as to what it could be?
-
JC, can you give me more information? What line in your code (not prototype) is causing the error?
-
That is the problem, I don't know what line of code is causing the problem. I don't know what the problem is. When I look at the stack it says the error is coming from this line: ERROR HERE->Event.observe(document.body, 'click', function(event) { if (Event.element(event).tagName == 'A') { staying_in_site = true; } }); I stepped into the prototype function and it said that element is null.
-
JC, do you have the code in the body or in the head? If it is in the head, document.body is null. You should either move the code to the body or wrap it with a dom:loaded event: http://www.prototypejs.org/api/document/observe.
-
Nice solution! I found an annoying bug though: when I refresh the page it pops up the alert. Does anyone have a solution to this?
-
Hello, I have a couple of questions about your solution (my js skills are poor so I apology if the questions look like silly) 1- what exactly the script should do? does it open a popup when the user closes the browser tab? If so 2- what have I to do in order to make it working? I copied the script at the end of my body page but nothing happens. Thanks and have a good 1!