Issue communication with postMessage from parent to child iFrame - javascript

I'm having an issue communicating from my parent window to the child iFrame. But in the other side, everything works perfectly.
Here is how I get the chil iFrame object in order to fire the postMessage function:
var iFrame = document.getElementById('Frame').contentWindow;
When I print it int he console, I get the following:
Window {parent: Window, opener: null, top: Window, length: 0, frames: Window…}
When I proceed to the postMessage function as follows:
iFrame.postMessage("message", "http://contoso.com");
It shows me an error when loading the page: iFrame.postMessage is not a function.
When I execute the postMessage in console, I get an undefined
What am I doing wrong ?

try this
var iFrame = document.getElementById('Frame');
iFrame.contentWindow.postMessage("message", "http://contoso.com");
I had this problem too. I found solution from this website https://www.viget.com/articles/using-javascript-postmessage-to-talk-to-iframes

I wasn't able to get this working using a querySelector approach.
What worked for me was the following. I'll refer to the two webpages as the parent that has an iframe on it and the src as the page inside the iframe.
On the src page, I post a message, with the parent url as the origin:
// src
window.parent.postMessage({
type: "connect",
url: window.location.href
}, "http://iframeparent.dev", );
Then in the parent page, I listen for this. It will have a property called source which is the iframe in question. This property can be posted to.
// parent
window.addEventListener("message", (event) => {
// this is the magic connection:
event.source;
}, false);
So you could do something like:
// parent
let sources = [];
window.addEventListener("message", (event) => {
sources.push(event.source);
}, false);
function something() {
sources.forEach(source => {
source.postMessage({some: "data"}, "http://iframesrc.dev")
})
}

Below code also works.
$('#id')[0].contentWindow.postMessage("hello world",targetOrigin);
There is a difference between jQuery selector and document.getElementById.
Document.getElementByID returns HTML DOM object.
jQuery selector returns jQuery object.
For more information please find below link.
document.getElementById vs jQuery $()

Related

Restore native Window method

For a script I'm writing, I'd like to use the native window.open method. However, a script already loaded to which I don't have access, overwrites the global window.open method with a boolean (ouch).
I know how to restore the methods on the Document (via HTMLDocument.prototype), but I don't know how to restore them on the Window, as I can't seem to find the equivalent for that to Window. Window.prototype.open does not exist for example.
I have tried creating an iframe, and getting the open method from that contentWindow in the iframe, but the browser will block opening windows using open because it was probably created in another origin. Neither delete open; does work because open was defined using var in the globally loaded script.
So, how can I restore the open method, defined as 'native code' in Chrome?
I know there are similar questions around, but actually the main question is:
Is there a equivalent of HTMLDocument for the Window object?
I've found this question and the accepted answer (using an iframe) could be used in your case.
The only issue is you can only use the retrieved version of window.open as long as the iframe is still in your document.
function customOpen() {
// local variables definitions :
var url = "https://stackoverflow.com", iframe, _window;
// creating an iframe and getting its version of window.open :
iframe = document.createElement("iframe");
document.documentElement.appendChild(iframe);
_window = iframe.contentWindow;
// storing it in our window object
window.nativeOpen = _window.open;
try {
window.open(url);
} catch (e) {
console.warn(e); // checking that window.open is still broken
}
window.nativeOpen(url);
// deleting the iframe :
document.documentElement.removeChild(iframe);
}
document.getElementById("button").addEventListener("click", customOpen);
Another JSFiddle
Keeping the workaround answer in case someone needs it :
Can you execute a custom script prior to the execution of the script that redefines window.open? If so, you could create a copy of the window.open in another global variable.
It could look like this :
1. First : a backup script
window.nativeOpen = window.open;
2. Then, whatever the window.open overwriting script does :
window.open = false; // who does that, seriously?
3. Your window opening script, that'll use your window.open copy :
function customOpen() {
var url = "https://stackoverflow.com";
try {
window.open(url);
} catch (e) {
console.warn(e);
}
window.nativeOpen(url);
}
JSFiddle example

How to postmessage HTMLIFrameElement?

I'm having issue passing HTMLIFrameElement object from parent site to iframe (located on a different domain) using postMessage method.
This is my code that I already tried:
var frame = document.getElementById('myHTMLIFrameElement');
frame = JSON.parse(JSON.stringify(frame));
event.source.postMessage(frame, "*");
Unfortunately, JSON.parse/JSON.stringify does not seem to be the right way of handling HTMLIFrameElement object. Can you please advise how to pass through HTMLIFrameElement object correctly?
Parsing DOM elements as JSON does not do anything useful as far as I know.
Since postMessage() is part of the window object, you could try using the window object of the frame, which is found under the contentWindow property of the iframe.
So you could try something like:
var frame = document.getElementById('myHTMLIFrameElement');
frame.contentWindow.postMessage( "stuffYouWantToSendToTheIframe", '*' );
And then in the script inside the iframe:
window.addEventListener('message', function( event ) {
// handle message
});

Cross Domain communication from Child (iframe) to Parent not working

I have a component within AEM (Adobe Experience Manager - a cms) on a page and I want to include this page onto another page (from a different domain) using an iframe. So in the code for the component I am using window.postMessage() and I'm trying to listen to that event in the parent. I have tried communicating the other way, parent to iframe and it worked fine, but I need to communicate the other way. So the component is a search component and when you click on a search result I want to redirect but from the parent window so I'm trying to send the URL to redirect to and then handle the redirection within the parent's JS code.
The code looks like:
(From the parent - html)
<iframe
width="1080"
height="700"
id="theFrame"
src="http://localhost:4502/content/zebra1/global/en_us/hey.html#q=print"
frameborder="0">
</iframe>
(From the parent - js)
function receiveMessage(e)
{
var key = e.message ? "message" : "data";
var data = e[key];
var redirect = JSON.parse(data);
redirectUrl = (redirect.origin ? redirect.origin : '') + (redirect.url ?
redirect.url : '');
if (redirectUrl) {
window.location.href = redirectUrl;
}
}
window.addEventListener("message", receiveMessage, false);
(From the iframe/child - js)
goToSearchResults : function( event ){
var windowOrigin = location.origin;
if( arguments[0].length == 3){
var redirect = {
origin: windowOrigin,
url: arguments[0][1].url || ''
};
if(!$('#supportSearchWrap').data('iframe')) {
location.replace(redirect.url);
} else {
window.postMessage(JSON.stringify(redirect), windowOrigin);
}
}
logger.log( redirect.origin + redirect.url , this.model );
}
It's not working for me. Does anyone see what I'm doing wrong or a better way to do this?
window.postMessage - The window refers to the instance of the window object to which you're posting your message. In your case, it should be the parent of the iframe window.
You can get that reference inside the iframe using window.parent or simply parent.
Also, the targetOrigin property should match the targeted window properties. From MDN docs, it is as below.
targetOrigin
Specifies what the origin of otherWindow must be for the event to be dispatched, either as the literal string "*" (indicating no preference) or as a URI. If at the time the event is scheduled to be dispatched the scheme, hostname, or port of otherWindow's document does not match that provided in targetOrigin, the event will not be dispatched; only if all three match will the event be dispatched.

postMessage() generates error "undefined is not a function"

I'm trying to get postMessage() to work to communicate between an iframe and my main website. However using the exact syntax given in the example code on MDN, I am being presented with a nice Undefined is not a function error. I've tried several things, such as initializing the iframe inside Javascript and appending it to my page, but that left me with the same error. Same for have seperate selectors to select my iframe.
I have the following Javascript code:
<script type="text/javascript">
$(document).ready(function() {
$('.editor').postMessage("A", "domain here");
});
function receiveMessage(event)
{
if (event.origin !== "domain here")
return;
// Do something
}
window.addEventListener("message", receiveMessage, false);
</script>
The script above tries to send a message to my iframe on the page, which looks like:
<iframe src="domain here/frameListener.html" class="editor"></iframe>
It then has a function receiveMessage to catch any messages being send as a response to the main webpage. Last but not least, I've tried the answers given in this question: But that did not fix my problem. It is therefore not a duplicate.
How can I get rid of this error message?
postMessage is not a jQuery function so you need to get the actual window DOM element and call it on that:
$('.editor').get(0).contentWindow.postMessage("A", "domain here");
Furthermore, you need to access the contentWindow property of the iframe. Here is an excerpt from the MDN docs:
otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow
A reference to another window; such a reference may be
obtained, for example, using the contentWindow property of an iframe
element, the object returned by window.open, or by named or numeric
index on window.frames.

Problems with window.postMessage on Chrome

I have been stuck on this for hours.
I have a.html on http://example.com that contains an iframe with src to
b.html on http://subdomain.example.com. a.html has some JS code
to postMessage to the iframe.
The code to postMessage is simple:
iframe_window.postMessage('message', iframe_element.src)
But this way, Chrome throws an error:
Unable to post message to http://subdomain.example.com. Recipient has origin null.
I have also tried:
iframe_window.postMessage('message', 'http://subdomain.example.com')
But NO LUCK!
This is the ONLY WAY it works:
iframe_window.postMessage('message', '*')
But I have heard '*' is not good to use.
No problems in Firefox.
It looks like this might be an issue with the child iframe not being loaded at the time the signal is sent, thus iframe.src doesn't have the proper value.
I did some testing and got the same error as you, but when I wrapped the postMessage call in a setTimeout and waited 100ms then there was no error, which tells me that this is an initialisation race condition.
Here's how I implemented a cleaner solution without the setTimeout:
Parent:
window.addEventListener("DOMContentLoaded", function() {
var iframe = document.querySelector("iframe")
, _window = iframe.contentWindow
window.addEventListener("message", function(e) {
// wait for child to signal that it's loaded.
if ( e.data === "loaded" && e.origin === iframe.src.split("/").splice(0, 3).join("/")) {
// send the child a message.
_window.postMessage("Test", iframe.src)
}
})
}, false)
Child:
window.addEventListener("DOMContentLoaded", function() {
// signal the parent that we're loaded.
window.parent.postMessage("loaded", "*")
// listen for messages from the parent.
window.addEventListener("message", function(e) {
var message = document.createElement("h1")
message.innerHTML = e.data
document.body.appendChild(message)
}, false)
}, false)
This is a simple solution in which the child will signal to anyone that it's loaded (using "*", which is okay, because nothing sensitive is being sent.) The parent listens for a loaded event and checks that it's the child that it's interested in that's emitting it.
The parent then sends a message to the child, which is ready to receive it. When the child gets the message it puts the data in an <h1> and appends that to the <body>.
I tested this in Chrome with actual subdomains and this solution worked for me.
A shorter solution is to wrap the postMessage inside iframe_element.onload function.

Categories

Resources