Differentiate among various forms of beforeunload occurrences

Can JavaScript differentiate between beforeunload events triggered by a user closing a browser tab versus clicking a mailto link?

I am looking to achieve the following:

window.addEventListener("beforeunload", function (e) {

    if(browserTabClosed) {
        // Perform one action
    }
    else if (mailtoLinkClicked) {
        // Perform another action
    }
}

Answer №1

A solution was discovered by examining the event (e below) that is passed in:

window.addEventListener("beforeunload", function (e) {

    // By accessing `e.target.activeElement.nodeName`,
    // we are able to determine what triggered the event.
    // - If the event was triggered by closing a browser tab: The value is "BODY"
    // - If the event was triggered by clicking a link: The value is "A"
    const isLinkClicked = (e.target.activeElement.nodeName === "A");

    // Perform an action if the event was triggered by clicking a link
    if (isLinkClicked) {
        // Do one thing
    }
    // Perform a different action if the event was triggered by closing the browser tab
    else {
        // Do a different thing
    }
}

Answer №2

The behavior of the beforeunload method varies across different browsers due to their attempts to prevent popups and malicious code from running within this handler.

Unfortunately, there is no consistent way to determine what triggered the beforeunload event in a cross-browser manner.

In your specific case, you can differentiate between the two desired behaviors by detecting a click on the window:

window.__exit_with_link = false;
window.addEventListener('click', function (e) {
    // check if user clicked on a link
    var isLink = e.target.tagName.toLowerCase() === 'a';

    // check if the link targeted the current page:
    // if it targets a popup/iframe/blank page,
    // the beforeunload event on this page will not be triggered
    var isSelf = !a.target.target || a.target.target.toLowerCase() === '_self';
    
    if (isLink && isSelf) {
        window.__exit_with_link = true;

        // reset after a short delay
        setTimeout(function(){ window.__exit_with_link = false; }, 50);
    }
    else { window.__exit_with_link = false; }
});

window.addEventListener('beforeunload', function (e) {
    if (window.__exit_with_link) {
        // user left the page by clicking a link
    }
    else {
        // user left the page for another reason
    }
}

While not ideal, this approach still functions. Similarly, additional handlers could be added to detect other reasons for the user leaving the page (such as using keyboard shortcuts like CTRL-R for refresh).

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Creating multiple nested ng-repeats in an AngularJS table

Managing a large amount of data on users' availability by hour for multiple days can be challenging. The data is structured as follows: availData = { "date1":arrayOfUsers, "date2":arrayOfUsers, ... } arrayOfUsers= [ userArray, userArray, ... ] user ...

What steps can I take to personalize Material UI within a React application?

As someone who is new to this UI framework and React, I have been tasked with developing an application that requires more design patterns. I specifically chose a framework that does not depend on jQuery code. However, I am facing challenges when it comes ...

Is there a way to dynamically create a Vue component for every tier of a nested JSON object without prior knowledge of the total number of tiers available?

I am working with JSON data that includes a list of retailers, some of which have subretailers that go multiple levels deep. My goal is to use Vue to generate markup that will show the parent retailer along with any nested subretailers underneath it, simi ...

MapBox notifies when all map tiles have finished loading

Currently, I am utilizing the Mapbox GL JS API to manipulate a Mapbox map. Prior to sending my result (which is a canvas.toDataURL) to the server via HTTP, I must resize my map to a larger resolution and then use fitbounds to return to the original points. ...

Loading content onto a webpage using AJAX

I am currently facing a challenge while attempting to incorporate a file on my server using AJAX. The issue I am encountering is that it disrupts the functionality of my PHP code. The AJAX is implemented on the following page: <div id="content&quo ...

Allowing the contenteditable attribute to function only on a single line of

My app allows users to create different lists, with the ability to edit the name. However, I am facing an issue where if a user types a new name, it should remain on only one line. I tried adding max height and overflow hidden properties, but it only hides ...

find all occurrences except for the last of a pattern in javascript

When considering the patterns below: "profile[foreclosure_defenses_attributes][0][some_text]" "something[something_else_attributes][0][hello_attributes][0][other_stuff]" It is possible to extract the last part by utilizing non-capturing groups: var rege ...

How can we access parameters in ag-Grid's Angular 1 onFilterModified event?

Currently, I am incorporating grid options using the code snippet provided below: var gridOptions = { columnDefs: columnDefs, rowData: null, enableFilter: true, onFilterChanged: function() {console.log('onFilterChanged');}, onFilterModified: fun ...

Enhancing Performance of D3 JS for Visualizing Large XML Data

I am working on visualizing a large XML file, almost 1 GB in size, as a graph of nodes and links using D3 Javascript. I am currently working with mac 10.5.8. I have successfully extracted the content of the file, displaying it as: [Object Element]. The p ...

Error in Blinking Tooltip when Hovering Skill Bubble (React and d3)

I've encountered a frustrating issue with tooltips on my website - they just won't stop blinking when I hover over the skill bubbles. I tried fixing the tooltips at a certain location, but whenever there's a bubble in that spot and I hover o ...

Executing a simulated onClick event in jQuery

Attempting to create a simulated onclick event on a drop-down menu has proved challenging for me. An IE object is being used to navigate to a page, where I need to modify a dropdown menu that contains an onchange event: $('select[name="blah"]') ...

Encountering a Typescript error while attempting to utilize mongoose functions

An example of a User interface is shown below: import {Document} from "mongoose"; export interface IUser extends Document{ email: string; password: string; strategy: string; userId: string; isValidPassword(password: string): ...

Problems arising from jQuery Mobile, NPM, and WebPack

After spending a considerable amount of time researching and experimenting, I am confident that I could piece something together to make it work. However, I would rather gain an understanding of the root cause of my issue. It is widely acknowledged that j ...

Encountered a JavaScript loading error during the installation of Sourcetree on a Windows 7

Encountering an error during the installation of Sourcetree on a Windows 7 (32-bit) system. Atlassian JavaScript load error We encountered issues while trying to load scripts. Please ensure that your network settings permit downloading scripts from this ...

When using getStaticPaths, an error is thrown stating "TypeError: segment.replace is not a function."

I am a beginner when it comes to using Next.js's getStaticPaths and I recently encountered an error that has left me feeling lost. Below is the code I have written (using query from serverless-mysql): export async function getStaticPaths() { cons ...

What is the most efficient way to update a particular item in an array within a React component's state while maintaining its conventional approach?

When working with React component state, I often struggle with manipulating a specific item in an array. Take this example: state={ menus:[ { id:1, title: 'something', 'subtitle': 'another something', switch ...

What is the reason behind having all bindings resolved during each $digest cycle?

Upon placing a breakpoint on a bound function, I discovered that it is being triggered every cycle. This came as a surprise to me as the timer displaying a countdown on the page was updating other properties as well. The demonstration below showcases thre ...

Issues with retrieving a result object from a MySQL query in NodeJS

I've been working on creating a logging system in NodeJS with a MySQL database. To establish the connection, I use the following code: const con = mysql.createConnection({ host : 'localhost', user : 'dbuser', passwor ...

MeteorJS encountered an issue stating "Invalid modifier. The modifier must be in object form."

After removing the if statements containing UserSession.insert, everything runs smoothly. However, when they are included, an error regarding an invalid modifier is triggered. What caused this issue? Your assistance is appreciated! server/helpers/b.s Me ...

Issues occurring with setting the variable using the Google latlng API

I've tried searching for solutions on various forums, including stackoverflow, but haven't been able to make it work. The issue lies in this code snippet where the variable 'pos' is not being set: var geocoder= new google.maps.Geocoder ...