on window close, not beforeunload

mmoore
mmoore used Ask the Experts™
on
I have a parent window which has a button which launches a popup window. The first thing the popup window does is to mask-out the parent window so that no data can be entered while the popup is open. The popup window is like a wizard which presents a series of forms with PREVIOUS and NEXT buttons. When the last form is presented, there is a FINISH button. When the user clicks on the FINISH button, the mask-out is removed from the parent window and then the popup window closes. This works perfectly. The only problem is, what happens if the user closes the window prior to reaching the FINISH button? Well, the parent window remains masked-out. I tried adding the following bit of code to the popup window.
  window.addEventListener('beforeunload', function () { 
     window.opener.document.getElementById("modalDivBackDrop").classList.remove("slds-backdrop--open");
   });

Open in new window

It works nicely when the user closes the popup window. Unfortunately it also triggered when the user hits the NEXT button. The NEXT button looks like:
<input id="j_id0:j_id1:i:f:pb:pbb:next" type="submit" name="j_id0:j_id1:i:f:pb:pbb:next" value="Next" style="visibility: visible;" class="btn FlowNextBtn">

Open in new window

I don't understand why the 'beforeunload' event is being triggered by the NEXT button.
I've tried various ways of unbinding the 'beforeunload' event from the <FORM> but no luck.
What do I need to do in order to unmask the window.opener.document when the user closes the popup but not when they click on the NEXT button.
Thanks
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Author

Commented:
I have solved my problem by using MutationObserver. I trap it when somebody changes the class on the DIV which causes the shield to drop. I then test if the popup still exists. If Yes, then I put the shield back down. Shield down means:

 window.opener.document.getElementById("modalDivBackDrop").classList.remove("slds-backdrop--open");

So rather that find the source of the problem and prevent it, I have chosen to monitor the symptom and fix it.
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
You need to post a message the parent window.

Parent
CSS
<style type="text/css">
.overlay {
  background: rgba(0,0,0,.85);
  position: fixed;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 10000;
}
</style>

Open in new window

HTML
	<button>Click Me</button>

Open in new window

JavaScript
<script>
$(function() {
  $('button').click(function() {
    $('body').append($('<div/>', {class: 'overlay'}));
    window.open('t2196child.html');
  });
});
window.addEventListener('message', function(e) {
  console.log(e.data);
  $('.overlay').remove();
}, false);
</script>

Open in new window

Child
<!doctype html>
<html>
<body>
<h1> Close this form</h1>
<script>
window.addEventListener('beforeunload', function() {
	window.opener.postMessage("done", window.location.href);
});
</script>
</body>
</html>

Open in new window

Working sample here

Author

Commented:
I should have made it more clear that the NEXT button is also triggering a 'beforeunload' event, and I can't change this because it's part of a visual flow (salesforce) embedded in a visualforce page. I don't need need anybody to look at this, but I am posting in just in case anybody is interested.
<apex:page showheader="false" sidebar="false">
<flow:interview name="New_Account_Wizard"></flow:interview>
<!-- New_Account_Wizard is a multi page flow with a form on each page -->
<!-- so at different stages of the flow the DOM will look different -->   
<script>

   window.onload = function () {
     var frm = document.getElementById('j_id0:j_id1:i:f');
     // do this only if the target FORM is on the curent page
     if (typeof(frm) != 'undefined' && frm != null)
     {
     
        var accountNameField = document.getElementById('j_id0:j_id1:i:f:pb:d:Company.input');
        // do this only if the target accountNameField is on the curent page
        if (typeof(accountNameField) != 'undefined' && accountNameField != null)
        {
           // Load the local Storage when the user hits the NEXT button. NEXT button does SUBMIT and goes to next page
           frm.addEventListener('submit',function(evt) {
               localStorage.setItem('AccountName', document.getElementById('j_id0:j_id1:i:f:pb:d:Company.input').value);
           });
        }
     }
     
     var finishBtn = document.getElementById('j_id0:j_id1:i:f:pb:pbb:finish');
     if (typeof(finishBtn) != 'undefined' && finishBtn != null)
     {
        // override the FINISH button on the last screen of the wizard. If you dont,
        // the natural behaviour is to restart the wizard at page one.
        finishBtn.addEventListener('click',function(evt2) {
            evt2.preventDefault();
            //console.log (document.body);
            //var list = (opener.document.body)
            
            // Remove backdrop which is covering the parent window
           // window.opener.document.getElementById("modalDivBackDrop").classList.remove("slds-backdrop--open");
            //console.log (list);

            window.close();
        });
     }
   }

    
 window.addEventListener('beforeunload', function () { 
 
    window.opener.document.getElementById("modalDivBackDrop").classList.remove("slds-backdrop--open");
    console.log('opened backdrop from popup window');
  });

</script> 
</apex:page>

Open in new window


The "<flow:interview name="New_Account_Wizard"></flow:interview>" basically injects a Visual Flow ( a multi form multi page web based app) at this point. This app has a NEXT button on it with takes the user to the next page but it ALSO also triggering a 'beforeunload'. I don't want to unmask the parent window each time the user hits the NEXT button. I only want to unmask  the parent window when the user actually closes the popup. Anyway, I've actually solved my problem albeit a bit hacky.  I'll leave this open for now just in case there is some solution that allows me differentiate between the user clicking on the close-window X button and hitting the NEXT button.
Capture.PNG
Ensure you’re charging the right price for your IT

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden using our free interactive tool and use it to determine the right price for your IT services. Start calculating Now!

Most Valuable Expert 2017
Distinguished Expert 2018
Commented:
I suspect what is happening is the Next button is calling another page which is what is triggering the beforeunload.

Not sure if this will work
What you would need to do is to attach an event handler to the Next and set a flag to say whether it has been clicked and in the beforeunload check to see if the flag has been set and only remove the background if the flag has not been set (button has not been clicked)

Author

Commented:
Awesome idea. I'll try that. It's a good technique. I doubt, however,  if it is the best solution in this case because the wizard (visual flow) might be changed independent of this usage. I think that each NEXT button might have a different id and if more next buttons get created (more pages to the wizard)  then I would need to update my wrapper to address these new buttons. In fact, that is a weakness that my wrapper (visualforce page shown above) already has. It looks for specific element ids and I have no guarantee  that the next time I generate the visual flow that it will be generated with those same ids.  Thanks for your help!
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
I would look for something that identifies the button other than its id - look for a class that you can use - even if it is a sibling you can do a next to get to the Next button.

Otherwise you are welcome.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial