Reputation: 849
I have an Angular 2 project and a NodeJs project. I have an iframe in Angular 2 app and I want to show NodeJS app in it. I would like to use postMessage() method from Angular2 to NodeJs and then reverse(from NodeJs to Angular2). Angular2 Address is http://localhost:3001 and NodeJs address is http://localhost:3005.
In Angular 2 I have a template in component like this;
template: `<iframe id="ifrm" #ifrm [src]="iframeURL()" width="500" height="200"> <p> Your browser does not support iframes</p> </iframe> `
iframeURL() {
return this.sanitizer.bypassSecurityTrustResourceUrl('http://localhost:3005');
}
@ViewChild('ifrm') iframe: ElementRef;
Exception: DOMException: Blocked a frame with origin "http://localhost:3001" from accessing a cross-origin frame.
this.iframe.nativeElement.contentWindow.postMessage('{}','http://localhost:3005');
Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('http://localhost:3005') does not match the recipient window's origin ('http://localhost:3001').
import {Component, OnInit, ElementRef} from '@angular/core';
import {DomSanitizer} from '@angular/platform-browser'
import {ViewChild} from "@angular/core/src/metadata/di";
@Component({
selector: 'app',
template: `<div> <iframe id="ifrm" #ifrm [src]="iframeURL()" width="500" height="200" style="/*display:none;*/"> <p> Your browser does not support iframes</p> </iframe> </div>`
})
export class AppComponent implements OnInit{
constructor(private sanitizer: DomSanitizer){}
@ViewChild('ifrm') iframe: ElementRef;
ngOnInit(){
console.log(this.iframe.nativeElement.contentWindow);
this.iframe.nativeElement.contentWindow.postMessage('{}', 'http://localhost:3005');
}
iframeURL() {
return this.sanitizer.bypassSecurityTrustResourceUrl('http://localhost:3005');
}
}
Upvotes: 2
Views: 9131
Reputation: 511
For simplifying code, you can use Renderer2
of Angular and you can use tag name instead of ElementRef
to get the iframe element.
import { Component, Renderer2, AfterViewInit } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Component({
selector: 'app-root',
template: `<iframe [src]="iframeURL" #iframeTagName (load)="loadIframe(iframeTagName)" style="visibility: hidden; position: absolute; left: 0; top: 0; height:0; width:0; border: none;"><iframe>`
})
export class AppComponent implements AfterViewInit {
iframeURL;
private isInited;
constructor(
private domSanitizer: DomSanitizer,
private renderer: Renderer2
) {
this.iframeURL= this.domSanitizer.bypassSecurityTrustResourceUrl('http://iframe-url.com');
}
loadIframe(iframeTagName) {
if (this.isInited) {
// post message to iframe
iframeTagName.contentWindow.postMessage('message' , 'http://iframe-url.com');
// You can receive response from iframe if any
this.renderer.listen('window', 'message', (event) => {
if (event.origin !== 'http://iframe-url.com') {
return;
}
// handle event here
});
}
ngAfterViewInit() {
this.isInited = true;
}
}
Upvotes: 0
Reputation: 93
This is how i handle the problem. only postMessage
after ngAfterViewInit
. Though it may not work for you, you can try it:
<iframe #iframe class="iframe-map" (load)="onIframeLoad()"></iframe>
import { Component, AfterViewInit, ChangeDetectionStrategy, ViewChild, ElementRef, Inject, Optional, Renderer } from '@angular/core';
import { URLSearchParams } from '@angular/http';
import { DialogRef, ModalComponent } from 'angular2-modal';
import { BSModalContext } from 'angular2-modal/plugins/bootstrap';
import { stringify } from 'querystringify';
import { AmapPickerOptions, AmapLocation, AMAP_PICKER_OPTIONS, AMAP_KEY, stringify as amapstringify } from '../amap';
export class AmapPickerModalData extends BSModalContext {
public center: string;
}
@Component({
selector: 'amap-picker-modal',
templateUrl: './modal.component.html',
styleUrls: ['./modal.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AmapPickerModalComponent implements ModalComponent<AmapPickerModalData>, AfterViewInit {
@ViewChild('iframe') iframe: ElementRef;
receiveMessage: EventListener;
private isInited: boolean;
constructor(
@Inject(AMAP_KEY) private key: string,
@Optional() @Inject(AMAP_PICKER_OPTIONS) private options: AmapPickerOptions,
private renderer: Renderer,
public dialog: DialogRef<AmapPickerModalData>) { }
ngOnInit() {
let center = this.dialog.context.center;
this.options = Object.assign({ key: this.key }, this.options, center && { center });
let query = stringify(this.options, true);
this.renderer.setElementProperty(this.iframe.nativeElement, 'src', `https://m.amap.com/picker/${query}`)
this.receiveMessage = (event: MessageEvent) => {
if (event.origin !== 'https://m.amap.com') {
return;
}
this.dialog.close(amapstringify(<AmapLocation>event.data));
};
}
ngAfterViewInit() {
this.isInited = true;
}
ngOnDestroy() {
window.removeEventListener('message', this.receiveMessage);
}
onIframeLoad() {
if (this.isInited) {
setTimeout(() => {
this.iframe.nativeElement.contentWindow.postMessage('hello', 'https://m.amap.com/picker/');
window.addEventListener('message', this.receiveMessage, false);
}, 500);
}
}
}
Upvotes: 6