2

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)

strawberrymilk
  • 392
  • 2
  • 10
  • Can you show us how you are adding `src` to iframes? – Vinay Jan 04 '20 at 02:17
  • Are the iframes src identical or is each one different? – zer00ne Jan 04 '20 at 02:18
  • @zer00ne each src is different. – strawberrymilk Jan 04 '20 at 02:49
  • share your code snippet. – Md. Amirozzaman Jan 04 '20 at 03:05
  • @MuhammadAmirozzamanNiaz [here's a jsfiddle of the parent page](https://jsfiddle.net/strawberrytittymilk/bqsro243/3/). iframe's have the same code but without the iframe tags, and both have been tested with the respective codes in my question. please let me know if i need to show more. – strawberrymilk Jan 04 '20 at 03:22
  • Do you want to just trigger clicks in
    s of
    – Vinay Jan 04 '20 at 05:30
  • @Viney Either way is fine. I was trying trigger a click on the div inside the iframe that would change the classes, but if if I can change the classes else way then that's even better. – strawberrymilk Jan 04 '20 at 05:53
  • I see but be sure to copy n paste those styles down in your ` – Vinay Jan 04 '20 at 06:03
  • @Viney my `iframes` have the same script, trigger div and css as the main page. Both the main page and the `iframes` have the same functions, and work the same way if someone were to visit the `iframe`s url. I'm just trying to have all the `iframes` triggers executed at the same time with only one click. – strawberrymilk Jan 04 '20 at 06:15

2 Answers2

1

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>
Vinay
  • 7,442
  • 6
  • 25
  • 48
  • Sorry if i'm misunderstanding you. In my iframe code, I use this `if(parent.document.querySelector(".toggled")` to trigger the div click if it's already been clicked before the iframe is loaded. I have no problems with this, that's why I didn't mention it in my post. My problem is if the div is clicked after the iframe is loaded. Also, I was only using the id for the sake of testing the code, which didn't work. I removed it when I removed the code. Thank you for your script, but it hasn't helped, unless I need to add something to my iframe page as well? – strawberrymilk Jan 04 '20 at 06:05
  • Oh perhaps I missed, could you pls elaborate more on _" My problem is if the button is clicked after the iframe is loaded."_? – Vinay Jan 04 '20 at 06:09
  • Basically everything I explained in my post. From my main page, when I click on `#btn` I am able to trigger a click inside an `iframe` that executes the script located in that `iframe`, but it only effects one iframe at a time. With the first code, I have to load the `iframe`s in order, and with the second code it only works on whichever iframe is loaded first. – strawberrymilk Jan 04 '20 at 06:25
  • This is strange it should not happen – Vinay Jan 04 '20 at 06:48
  • it only happens when the iframes are loaded on click :( otherwise it works great. i tried your code again and it doesn't have that problem at all, the only issue now is if i click _then_ unclick before the iframe is loaded, the iframe still registers as the parent having the `.toggled` class, even though the second click removed it. your code is the closest i've gotten to it working properly, so thanks for that! – strawberrymilk Jan 04 '20 at 07:12
  • You can maintain a flag in each – Vinay Jan 04 '20 at 09:56
  • Yes this fixed the problem! It's all working perfectly now, thanks so much for your help! – strawberrymilk Jan 05 '20 at 03:07
1

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.

Richard
  • 7,037
  • 2
  • 23
  • 76
  • I ran the html file like you said but I'm still experiencing the same problem. My goal is for the css to be the same in both the parent page and all 3 iframes at the same time, with a one click toggle for all. I think we are on the same page per your explanation, however, with your html I still have to click the buttons inside each iframe manually. – strawberrymilk Jan 04 '20 at 08:51
  • Everything is working great!!! The only thing I changed is putting the iframe urls back in the href. I kept the `./index.html` because I didn't know what else to put there. If there's anything else I _should_ change, please do tell. Otherwise I'm just glad everything's finally working properly. Thanks so much for your help!! – strawberrymilk Jan 04 '20 at 09:36
  • Also one last question. There were other elements on the main page that I wanted to toggle, not just `body`. For example I also wanted to toggle `.mydiv`, whereabouts in your code do I place that? – strawberrymilk Jan 04 '20 at 09:44
  • @strawberrytittymilk For your first comment: it should work **without** clicking anything inside each iframe manually. Are you sure that it's not working as intended? I tried running that code myself in my local PC before submitting my answer and it worked as expected. – Richard Jan 04 '20 at 12:26
  • @strawberrytittymilk For your second comment: the `./index.html` code section is to change the `src` of the `iframe`. What that does is that it changes the content of the webpage the `iframe` should display (in this case, it is that page itself). You can change the `src` to practically any other webpage you want, but do make sure that there each webpage that serves as a source for the `iframe` has an element with the `id` `btn` that toggles something (because we're performing a `click` on said webpage to toggle "night mode"). – Richard Jan 04 '20 at 12:28
  • @strawberrytittymilk That should be apparent. It's not that I don't want to give the answer, but if you understand the code I shared as an answer above, you should be able to figure it out ;-) So my suggestion is, try harder first (I want you to learn too!). I'm sure you can do it. If you still can't, don't hesitate to notify me through comment. – Richard Jan 04 '20 at 12:30