How to create click event across MULTIPLE iframes (same domain)?

2.8k Views Asked by At

I have a main (parent) page that hosts 3 iframes that are under the same domain. The iframe's src attribute is added on a click event, so the iframe's aren't loaded until needed.

What I want is when I click a certain div on my main page, it will trigger a click on a specific div that's located inside all 3 iframes at the same time.

I have tried the following code in my parent page:

function myFunction() {
  var iframe = document.getElementById("iframe1");
  var elmnt = iframe.contentWindow.document.getElementById("btn").click()
}

and repeated it twice more for iframe's #iframe2 and #iframe3. However, it didn't work unless I loaded the iframes in order that they're written on my page. (i.e the click event on #iframe2 didn't execute until after #iframe1's event). This is a problem as I'm unable to control what iframe visitors will load first. I tried giving them separate function() names, but the same thing occurred - only one iframe was effected at a time. Note, this worked fine when I tested it out with the iframe's already having their src's like normal, just not when they're added manually.

I also tried adding this in the iframe pages:

parent.document.getElementById('btn').onclick = function(){
 document.getElementById('btn').click();
}

However, this only works on the first iframe that is loaded (i.e if #iframe2 is loaded first, then the iframe1's and iframe3's event wont execute)

Is there any other solutions I could try? My purpose is creating a day and night toggle with classList.toggle, and I want all the iframes css to be toggled at the same time, with the toggle button being on the main page.

(I prefer vanilla javascript for my main page, but am fine with jQuery on the iframe pages)

2

There are 2 best solutions below

7
On BEST ANSWER

You are dynamically loading iframe's src suppose user loads <iframe3> but your code is written such a way that it tries to do something with <div> inside <iframe1> (which isn't loaded yet) what will happen? It will throw error and break the execution that's why it's not working for you what you need is to first look whether they are currently there Also you are using var iframe = document.getElementById("iframe1"); but I don't see any id on the fiddle you posted

Try this

<body>

<style>
body {
  background:#fff;
  color:#000
}

body.toggled 
{
    background:#000;
    color:#fff
}
</style>

<div id="btn">click here to toggle css</div>
<p>page content</p>

<a href="/iframe1" target="iframe1">add src to iframe one</a><br>
<a href="/iframe2" target="iframe2">add src to iframe two</a><br>
<a href="/iframe3" target="iframe3">add src to iframe three</a>

<p>iframe 1:</p>
<iframe src="about:blank" id="iframe1" name="iframe1"></iframe>

<p>iframe 2:</p>
<iframe src="about:blank" id="iframe2" name="iframe2"></iframe>

<p>iframe 3:</p>
<iframe src="about:blank" id="iframe3" name="iframe3"></iframe>
</body>

<script>

    document.querySelector('#btn').addEventListener('click', function(e) {
    [].map.call(document.querySelectorAll('body,a'), function(el) {
     el.classList.toggle('toggled');
    });


    var iframe1 = document.getElementById("iframe1");
    var iframe1btn = iframe1.contentWindow.document.getElementById("btn");
    if(iframe1btn) //<-- check if that element really exists within <iframe>
        iframe1.contentWindow.document.getElementById("btn").click()
    // you could've also used <iframe>'s loaded event but this is better way

    var iframe2 = document.getElementById("iframe2");
    var iframe2btn = iframe2.contentWindow.document.getElementById("btn");
    if(iframe2btn)
        iframe2.contentWindow.document.getElementById("btn").click()

    var iframe3 = document.getElementById("iframe3");
    var iframe3btn = iframe3.contentWindow.document.getElementById("btn");
    if(iframe3btn)
        iframe3.contentWindow.document.getElementById("btn").click()

});

</script>
6
On

I am not particularly sure what you got wrong on, but I think I understand what you want to do. To reproduce this example, please create a HTML file (with name index.html) in your local PC and run this file on your browser:

<!DOCTYPE html>
<html>
  <head>
    <style>
      body {
        background: #fff;
        color: #000;
      }


      body.toggled {
        background: #000;
        color: #fff;
      }
    </style>
  </head>
  <body>
    <div id="btn">click here to toggle css</div>
    <p>page content</p>

    <a href = "" target="iframe1">add src to iframe one</a><br>
    <a href = "" target="iframe2">add src to iframe two</a><br>
    <a href = "" target="iframe3">add src to iframe three</a>

    <p>iframe 1:</p>
    <iframe src="about:blank" name="iframe1"></iframe>

    <p>iframe 2:</p>
    <iframe src="about:blank" name="iframe2"></iframe>

    <p>iframe 3:</p>
    <iframe src="about:blank" name="iframe3"></iframe>

    <script>
      let outerBody = document.querySelector('body')
      let toggleButton = document.querySelector('#btn')
      let iframes = document.querySelectorAll('iframe')
      let anchors = document.querySelectorAll('a')

      toggleButton.addEventListener('click', () => {
        let body = document.querySelector('body')
        body.classList.toggle('toggled')
        Array.from(iframes).forEach(iframe => {
          toggleIframe(iframe)
        })    
      })

      Array.from(iframes).forEach(iframe => {
        iframe.addEventListener('load', e => {
          toggleIframe(iframe)
        })
      })

      Array.from(anchors).forEach(anchor => {
        anchor.addEventListener('click', e => {
          let targetedIframe = document.querySelector(`iframe[name=${anchor.target}]`)
          targetedIframe.src = './index.html'
        })
      })

      function toggleIframe(iframe) {
        let iframeBody = iframe.contentWindow.document.querySelector('body')
        let iframeToggleButton = iframe.contentWindow.document.querySelector('#btn')
        let isOuterBodyToggled = outerBody.classList.contains('toggled')
        let isIframeBodyToggled = iframeBody.classList.contains('toggled')

        if (isOuterBodyToggled && iframeToggleButton && !isIframeBodyToggled)
          iframeToggleButton.click()
        else if (!isOuterBodyToggled && iframeToggleButton && isIframeBodyToggled)
          iframeToggleButton.click()
      }
    </script>
  </body>
</html> 

I changed your a's href to empty (#). I also changed your JS file. Basically, I specified the as to change the source of its associated iframe when it's clicked with addEventListener('click'). Also, each time I click on the outerBody's (parent browsing context) button, I will also toggle its containing iframes' body by performing a click on the iframes' buttons. That already works. However, your problem was that you don't know when the iframes will be loaded. There's a function for that, addEventListener('load') on your iframes. When an iframe is loaded (an iframe will be loaded again when its source is changed), I will use that event listener to check if its parent browsing context's body is toggled. If it is, then simply toggle the iframe's body too by performing click.

Voila, it works. As mentioned, please try pasting the code above to your local file in your PC and run it in a browser.