100

I need to perform some action before a popup window(using window.open ) closes.

Something like will be good:

var new_window = window.open('some url')
new_window.onBeforeUnload = function(){ my code}

How can I achieve that?

Cᴏʀʏ
  • 105,112
  • 20
  • 162
  • 194
xiaohan2012
  • 9,870
  • 23
  • 67
  • 101

9 Answers9

153

While the accepted answer is correct for same origins I found a solution for cross origin popups:

var win = window.open('http://www.google.com'); 
var timer = setInterval(function() { 
    if(win.closed) {
        clearInterval(timer);
        alert('closed');
    }
}, 1000);

Source: atashbahar.com

For those considering using it.

Even Facebook is using this "hack" in their Javascript SDK.

You can verify this by having a look at their code. Just search for .closed in https://connect.facebook.net/en_US/sdk.js.

Dustin Hoffner
  • 2,025
  • 1
  • 14
  • 15
  • 5
    Nice one. Thanks! – Roshana Pitigala Mar 11 '18 at 09:47
  • 7
    I don't believe this is specifically a hack for cross-origin, it's actually the only accurate way to detect that the window has closed. The unload and beforeunload events are fired whenever the document within the window is unloaded, which could be due to a redirect or reload so it doesn't necessarily mean the window was closed. – hemp Mar 15 '18 at 23:27
  • This does not appear to work in Microsoft Edge, unfortunately – Jamie McCrindle Jul 24 '18 at 22:16
  • I just tested it on IE11 - WIN7: `var win = window.open('https://www.google.com/')` When the user allows popups the `win` variable will contain the expected object. Of course you have to call this with a user-triggered event. (e.g. `onClick` on something) – Dustin Hoffner Apr 17 '19 at 09:58
  • 2
    I've just tested the solution using Edge (March 2021) where I was monitoring window closed events for the same domain i.e. additional windows opened then closed within my app and this works nicely! – OJB1 Mar 13 '21 at 19:17
  • 1
    Be aware! If the popup is blocked, this setInterval will run INFINITELY – Arun Joseph Sep 24 '21 at 09:46
  • Doesn't seem to work win.closed is set true without closing the window. – Barış Uşaklı May 12 '22 at 21:38
  • 1
    This approach works for me, however win.close sets as true even when the URL inside the opened window(win) gets changed. Is there a way to avoid it and only execute when the win gets actually closed? @DustinHoffner – sumukha hegde Mar 15 '23 at 11:29
103

Your example will work as long as the pop-up window url is in the same domain as the parent page, and you change the event to all lowercase:

var new_window = window.open('some url')
new_window.onbeforeunload = function(){ /* my code */ }
posit labs
  • 8,951
  • 4
  • 36
  • 66
glortho
  • 13,120
  • 8
  • 49
  • 45
  • 8
    What if the newly opened window is not in the same domain with the parent window? Is there any hack? – xiaohan2012 Feb 22 '12 at 06:06
  • 13
    The best you could do is open a document in your domain that then loads the remote URL in an iframe, or reads it in via server scripts and renders it from there. – glortho Feb 22 '12 at 06:23
  • 1
    @glortho Does this approach has any advantage over defining the onbeforeunload event inside the new_window? More specifically, if this will bind the code immediately with the new_window, even before the new_page and it's scripts are loaded? – Khadim Ali Sep 08 '15 at 10:46
  • 1
    @xiaohan2012 There is a hack. See my answer https://stackoverflow.com/questions/9388380/capture-the-close-event-of-popup-window-in-javascript/48240128#48240128 – Dustin Hoffner Jan 13 '18 at 18:35
  • 4
    This is not actually an accurate method to detect that the window has closed. The unload and beforeunload events are fired whenever the document within the window is unloaded, which could be due to a redirect or reload, for instance. See @DustinHoffner's answer (https://stackoverflow.com/a/48240128/51055) for an accurate method. – hemp Mar 15 '18 at 23:40
  • It won't work with redirects as well, so suppose if you have an OAuth flow then even if your redirect URI has the same domain it won't work. – Raj Shah Jan 30 '20 at 21:13
13

The event name is onbeforeunload and not onBeforeUnload. JS is case sensitive.

valentinas
  • 4,277
  • 1
  • 20
  • 27
  • 2
    if we attach events by using on it attaches it as inline property to html and html is incase sensitive what means this will make absolutely no difference – nikoss Aug 08 '15 at 02:28
10

You need to bind the onbeforeunload event to the window AFTER it is opened.

The simplest way to do that would be to have the javascript onbeforeunload code within the window source code.

For detailed explanations, refer to these two very similar questions here and here on Stackoverflow.

Community
  • 1
  • 1
random_user_name
  • 25,694
  • 7
  • 76
  • 115
  • 1
    Thank you. Indeed `onbeforeunload` and `onunload` MUST be bounded AFTER the child window has loaded to work correctly. – Xavi Dec 09 '13 at 22:11
5

onbeforeunload event must be added after loading of pop-up window. For example, you can add it at the end of its load event like below;

const new_window = window.open('some url')
new_window.onload = function(){ 
    /* my code */ 
    this.onbeforeunload = function(){ /* my code */ }
}
Reza
  • 3,473
  • 4
  • 35
  • 54
5

You probably do not want to overwrite the value of onbeforeunload, because this will interfere with the popout's handler if it also uses that hook.

Use addEventListener('beforeunload', ...) instead.

const wnd = window.open(theUrl)
wnd.addEventListener('beforeunload', () => {
  // do stuff
})

Please note, other options exists for events, such as unload and pageHide. Read docs to see what event is best for your implementation.

For reference:

https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event

https://developer.mozilla.org/en-US/docs/Web/API/Window/unload_event

https://developer.mozilla.org/en-US/docs/Web/API/Window/pagehide_event

For an overview of the page lifecycle, see:

https://developers.google.com/web/updates/2018/07/page-lifecycle-api#developer-recommendations-for-each-state

Steven Spungin
  • 27,002
  • 5
  • 88
  • 78
3
import { useEffect, useRef } from "react";

const usePopupWindow = ({
  url,
  onPopupClose,
  popupProperties = "width=200,height=200",
}) => {
  const timer = useRef();

  const handleWindowPopup = () => {
    const windowPopup = window.open(url, "popup", popupProperties);

    timer.current = setInterval(() => {
      if (windowPopup.closed) {
        clearInterval(timer.current);
        onPopupClose();
      }
    }, 1000);
  };

  useEffect(() => {
    return () => clearInterval(timer.current);
  }, []);

  return { handleWindowPopup };
};

export default usePopupWindow;

Created this hook for React use case

1

As stated above, you need to bind the onbeforeunload event to the window after it is opened.

See example in other thread: https://stackoverflow.com/a/25989253/578275.

Community
  • 1
  • 1
-1
var new_window = window.open('some_url')

You can also check if new_window.window is null. But you need to manually check it with setTimeout or setInterval functions.

This is btw the only way how to check it when you are not on the same domain.

Petr Odut
  • 1,667
  • 14
  • 7
  • This is useful if you have a global method that opens and manages windows for you, and the url may be internal or external depending on the context – jimconte Dec 06 '17 at 15:43