0

I have an iframe that changes src pages when the page would normally switch to another page so that my main JS file can continue running in the background. For the first page, the one defined in the HTML src for the Iframe, I can access the inner document just fine by using iframe.contentDocument.

However, when I change the src, the contentDocument does not change with it, and I cannot access the Iframe's document in the JS at all.

So is there any way to access the new document of an Iframe after changing its source in JS? Or is there an easier alternative for the way I am doing things? Thanks.

How I've tried:

iframe.src = "pages/home/home.html"
innerDoc = iframe.contentDocument || iframe.contentWindow.document

and the innerDoc does not change from the original page. I've even tried making an entirely new Iframe that never had the original page as its src

document.body.removeChild(iframe)
let i = document.createElement('iframe')
i.src='pages/home/home.html'
document.body.appendChild(i)
innerDoc = i.contentDocument || i.contentWindow.document

This just makes innerDoc an empty HTML document with an empty head and body.

3
  • you must understand that an iframe represents an independent page which instead of being in a new tab of your browser is simply positioned inside your page. the only way to establish communication between your 2 pages, (internal and external) is to use messages. Commented Nov 14, 2022 at 23:12
  • But I am able to access the document on the first Iframe before the switch? And how would I use messages? Commented Nov 15, 2022 at 12:10
  • If the page inside the iframe is from your same domain, you don't need messages. If it's from another domain, you will need messages. Whenever you change the URL, you must wait for the page "load" event before accessing its content - something like i.contentWindow.addEventListener("load", ...) Commented Nov 15, 2022 at 17:48

2 Answers 2

1

It appears that the page you are loading inside the iframe is from the same domain as the parent window - so you should not need messaging.

You will, however, need to wait for the "load" event before accessing the page content. This is the same for any webpage, not just one embedded in an iframe. Note that you cannot access the contentWindow for an iframe until it is attached to the DOM:

let i = document.createElement('iframe');

// go ahead and attach it to the dom - you can "hide" it with css
document.body.appendChild(i);

// now that you can access the contentWindow, attach a "load" event
i.contentWindow.addEventListener('load', () => {
  // now you should be able to access the content
});

// do this last to avoid race conditions with caching and what not
// this might not be necessary, but it doesn't hurt
i.src='pages/home/home.html'

You can "hide" the iframe off screen if you want with something like this:

iframe {
  position: absolute;
  top: -9999em;
  width: 1px;
  height: 1px;
}
Sign up to request clarification or add additional context in comments.

2 Comments

It appears that the load event is never called. I put a console.log inside the function where it is supposed to run after it loads, and nothing happens.
Try adding the listener to the iframe itself: i.addEventListener('load', ...)
0

the "messaging" way is using Window.postMessage

parent Page:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>main Page</title>
  <style>
    body             { font-size: 16px; font-family: Arial, Helvetica, sans-serif; }
    iframe           { width: 24em; height: 15em; border:3px solid blue; }
    #get-iframe-info { width: 24em;  border: 1px solid orange; padding: .5em; }
   </style>
  </head>
<body>
  <h4>main page</h4>

  <p>parent input :
    <input  id="in-txt" type="text" placeholder="type something">
    <button id="Bt-Send2iFrame">Send2iFrame</button>
  </p>

  <p> iframe part : <br>
    <iframe id="iFrame-01" src="page_iFrame.html" frameborder="0"></iframe>
  </p>

  <p id="get-iframe-info">iframe return: <br>> &nbsp;  
    <span></span>  
  </p>

  <script>
    const
      inTxt       = document.querySelector('#in-txt')
    , btSend      = document.querySelector('#Bt-Send2iFrame')
    , iFrame01_ct = document.querySelector('#iFrame-01').contentWindow
    , sp_getiFram = document.querySelector('#get-iframe-info span')
      ;
    btSend.onclick =_=>
      {
      let info = { txt: inTxt.value }
      iFrame01_ct.postMessage( JSON.stringify(info), "*")
      }
    window.onmessage=e=>
      {
      let info = JSON.parse( e.data )
      sp_getiFram.textContent = info.txt   
      }
  </script>
</body>
</html> 

iFrame page(s)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
  <style>
    body { font-family: 'Courier New', Courier, monospace; font-size: 14px;}
    p    { width: 20em;  border: 2px solid aquamarine; padding: .5em; }
  </style>
</head>
<body>
  <h4>page iFrame</h4>
  <input  id="inTxt" type="text" placeholder="send text"> 
  <button id="btSend">send to parent</button>
  <p  id="get-parent-info"> info from Parent: <br>>&nbsp;
    <span></span>
  </p>
<script>
  const sp_infoParent = document.querySelector('#get-parent-info span')
    ;
  btSend.onclick =_=>
    {
    let info = { txt: inTxt.value }
    window.parent.postMessage( JSON.stringify(info), "*")
    }
  window.onmessage=e=>
    {
    let info = JSON.parse( e.data )
    sp_infoParent.textContent = info.txt   
    }
  </script>
</body>
</html> 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.