Angular8 IFrame before beforeunload event

1k Views Asked by At

I have an angular application which is kind of the main application that hosts sub application inside it. The sub applications are also angular applications. The way that I load sub application is through Iframes.

The sub-applications are shown as a list and when I click on an tab, that application is loaded. When I am making some changes to the data in an application and if I click on another sub-tab, I wanted to show a warning message saying " changes will be lost". I am able to achieve it by using beforeunload event as below. I can check to see if there are any unsaved changes and show the warning popup.

  @HostListener('window:beforeunload', ['$event'])
  unloadNotification($event: any) {
      if (**my logic here) {
          $event.returnValue =true;
      }
  }

The only problem with this is, when I click the other sub-tab, the host application highlights that sub-tab and then the warning pop-up is shown. If I click on stay button on the popup, I am able to be on the sub-tab I want but on the host application the other sub-tab is highlighted. So I am trying to see a way to not highlight the other tab if I want to stay on the current sub-tab. Something before beforeunload.

4

There are 4 best solutions below

5
Vincent On BEST ANSWER

In child app

const origin = this.getCurrentHostOrigin();
if (cancelSwitchTab) {
    window.parent.postMessage({}, origin); 
}

In host app:

this.renderer.listen(this.windowsRef.nativeWindow, 'message', event => {
  const message = event.data;
  *** your logic to revert highlight to current tab ***
});
2
talhature On

My understanding is you have to update an existing project that's been constructed in such a way that the beforeunload event is employed to achieve something similar to the Angular feature called route guards. You do or don't load the selected iframe depending on your logic implemented with the help of beforeunload event. You don't seem to favor changing this implementation that's why seeking a solution that covers your requirement applying a similar approach like another window event.

If my understanding is correct, you need to refactor this implementation so that the "guarding" happens depending on the inner workings of the "host application" where it actually has to be in the first place. The issue you have arises because by the time the iframe's unload event is canceled, host application's canceled tab gets already selected.

In short, this seems to be handled in your tab's selection event. My answer may or may not propose a solution you would accept, since we don't have all the details like which component suit you use, I can only present a pseudo solution:

Inside the component where your navigation tab's ui logic takes place:

onTabSelected(selectedIndex) {
    if (..your logic here) {
        loadIframe(selectedIndex);
        highlightTab(selectedIndex);
    }
}
0
Aakash Garg On

There is no such event as before beforeUnload. Two applications i.e. host and child can communicate via postMessage. so in beforeUnload event you can send a postMessage to child application to highlight existing tab. for eg:- let say you had reference of child window in variable name child1.

  child1.postMessage('{'tabId': 'tab1'}');

Your child application can receive this message and highlight the tab with identifier tab1.

0
Nicu On

Maybe we can create a communication system using the window.top object for example let's say that in the child apps you assign some id.

Then in the main app which hosts the others you create a subobject to window.top.appsMap = {};

Then from each child app you update a boolan value for example

window.top.appsMap['applicationId'] = hasChangesOrNot

Then from the top app where you change tabs you can check if the current opened tab app id has changes and not switch the tab but just try to unload the current iframe, it's not the best solution but if should work you can maybe also set some communication channel backwards which would trigger from the main app which hosts the others the save from the child app