11

Assume I have several iframes on the page and one of them sent a post message. Is there a simple and crossbrowser way to detect which one did it and be able to reply?

I see the source property of the message event but I am unable respond by using event.source.contentWindow.postMessage on it:

Error: Permission denied to access property 'contentWindow'

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
user2281966
  • 121
  • 2
  • 6
  • 3
    If somebody will look for solution for the same problem I can share what I have found. Just send iframe ID in message with other data. Simple way read ID of iframe within this iframe is set it similar whith "name" attribute and get window.name property during work. – user2281966 Oct 18 '13 at 14:48

4 Answers4

11

You can detect IFrame without names, just use comparison iframe.contentWindow === event.source.

window.addEventListener('message', function (event) {
  var iframes = document.getElementsByTagName('IFRAME');

  for (var i = 0, iframe, win; i < iframes.length; i++) {
    iframe = iframes[i];

    // Cross-browser way to get iframe's window object
    win = iframe.contentWindow || iframe.contentDocument.defaultView;

    // Comparison
    text.innerText += iframe.src +
      (win === event.source ? ' MATCHES.\n' : ' is not our IFrame.\n');
  }
});

// Creates iframe and sends postMessage from it
function createIFrameWithMessage(id) {
  var iframe = document.createElement('IFRAME');
  iframe.src = 'javascript:parent.postMessage("IFrame #' + id + '", "*");';
  document.body.appendChild(iframe);
}

createIFrameWithMessage(1);
createIFrameWithMessage(2);
createIFrameWithMessage(3);
<p id="text"></p>
mcmimik
  • 1,389
  • 15
  • 32
  • this works beautifully thanks so much - it may (or may not) be useful here to add data attributes to the iframe – danday74 Dec 15 '22 at 13:16
4

iframe

<script>
    document.addEventListener('mousedown',event =>
        parent.postMessage({ name: window.name }, window.location.origin)
    );
</script>

parent window

<script>
   window.addEventListener("message", event => {
       if (event.origin != window.location.origin) return;
       console.warn(event.source.frameElement.name);
       // here you can find your iframe by name
   });
</script>
<iframe name='myname1' src='/url1'/>
<iframe name='myname2' src='/url2'/>
<iframe name='myname3' src='/url3'/>
3

just use event.source.postMessage

danday74
  • 52,471
  • 49
  • 232
  • 283
klambiguit
  • 527
  • 1
  • 3
  • 14
  • I guess this was downvoted because it's a very brief answer but... this is actually the most elegant way to do this I think. – wopolow Jan 03 '23 at 16:24
0
function getIFrameThatSentMessage(message) {
    let allIFrames = Array.from(document.querySelectorAll("iframe"));
    return allIFrames.find(
        iframe => iframe.contentWindow == message.source
    );
}

window.addEventListener("message", (event) => {
     console.log(getIFrameThatSentMessage(event);
});

This question is already answered, but for anyone else looking for a concise way just to detect which IFrame sent the message, I came up with the function above.

The 'message' object passed to the getIFrameThatSentMessage function corresponds to the event you will receive when listening for messages.

Christian May
  • 127
  • 11