Angular 2 iframe to parent communication

2019-03-15 14:39发布

in my current project I have multiple Angular 2 applications which should be served by a portal application (also Angular 2). So the portal app has a header area with links to all underlying apps. When the user clicks on one app link, the corresponding angular 2 app gets loaded in an iframe of the portal body.

enter image description here

Now I develop a central authorization service. In the portal I have a service which holds the permissions of the current logged-in user. My question is: Is it possible to access angular 2 services / components of the parent (portal) within the individual apps (iframe)? It seemed to be possbile in angular 1 via scope

2条回答
再贱就再见
2楼-- · 2019-03-15 15:19

I am looking at doing something similar at the moment (a portal application with sub apps in an iFrame) You can communicate between your server and client (in either direction) by using window.postMessage to send data.

So for example on the server app:

var iframe = document.getElementById('useriframe');
    if (iframe == null) return;
    var iWindow = (<HTMLIFrameElement>iframe).contentWindow;

    iWindow.postMessage({"for":"user","data":"anything"}, 'http://localhost:4001');

and on the client app (hosted within the iFrame)

export class AppComponent {

@HostListener('window:message',['$event'])
onMessage(e)
{
if (e.origin!="http://localhost:4200")
  {
  return false;
  }
if (e.data.for=="user")
  {
  alert('here i am');
  }
}

Showing child frame routes in the parent So, in my implementation we pass tokens and user information from the shell application to the child iFrame, and we pass routing information from the child applications back to the shell so that the url reflects the route selected in the child application. In a child application you may have a route such as:

[userapp]/edituser/username

, and we wish to post it to the parent application and display the route like:

http://mywebsite/main/application/user#edituser/bob

Note that we use hashtag to mark a child route, and in your child applications you intercept every navigation event and post the new route via

export class MyRoutingComponent implements OnInit {
constructor(private router: Router) { 
router.events.subscribe((event: Event)=>{
  if (event instanceof NavigationEnd){
        let url=(<NavigationEnd>event).url;
        if (url.length>1)//don't post message about base route '/'
          window.parent.postMessage({"for":"dashboard", "operation":"changeroute","route":url},'*')
  }

})
}

and then in the parent application parse the message and use it to update the location path displayed.

    url = url +'#' + route;            
    this.location.go(url);
查看更多
你好瞎i
3楼-- · 2019-03-15 15:30

Hi really appreciate the solution given by @jazza1000 it helped me out.

Our problem was in the current (to date) version of angular cli there is a bug that prevents the use of external JS files even with allowJs. We would be using jsplumb (external js) to represent some flow charts. (Actual issue on stack overflow)

So we decided to go with the approach of hosting the functionality that uses external JS in an additional angular 4 application. And the parent angular 5 application will bring in the angular 4 application with iFrame. So when the user would want to view the flowchart we would open angular4 application in iframe then once he is done he would click save in the angular 4 application that would save all his modification followed by sending the message to parent window that would close/hide the div with iframe.

Our parent application in angular 5 has the code

 @HostListener('window:message', ['$event'])
  onMessage(e) {
    debugger;
    if (e.origin != "http://localhost:4201") {
      return false;
    }
    if (e.data.for == "user") {
      alert('here i am');
    }
  }

Our iFrame angular 4 application on save button has the code (we are starting the application with --port 4201)

window.parent.window.postMessage({"for":"user","data":"anything"}, 'http://localhost:4200')
查看更多
登录 后发表回答