Search code examples
javascripthtmliframe

How to send a message to the iframe whose src has been changed


I am working on an html page which hosts a iframe and will change depending upon situation. The iframe src change is easily accomplished but sending message to that iframe (through iframe.contentWindow.postMessage) isn't happening. I did some test run and saw that message being displayed on previous iframe.

After that I thought of using asynchronus approach (tries async/await and promise also) thinking my problem has to be because of that but the problem still persisted.

I am working with vanilla js and below is simplified snippet of codes.

Main index page

<!DOCTYPE html>
<html lang="en">
<body>
   <iframe id="bodyChange" src="pubMode.html" frameborder="0"></iframe>
   <script src="../script/popup.js"></script>
</body>
</html>

Now, below are html pages which have to be in iframe.

pubMode.html

<!DOCTYPE html>
<html lang="en">
<body>
    <button id="settingBtn">Setting</button>
    <button id="privMode">Private Mode</button>

    <div id="container"></div>
   <script src="../script/frame.js"></script>
</body>
</html>

setting.html

<!DOCTYPE html>
<html lang="en">

<body>
    <div id="settingPage"></div>

    <script src="../script/setting.js"></script>
</body>

</html>

privMode.html

<!DOCTYPE html>
<html lang="en">

<body>
    <button id="settingBtn">Setting</button>
    <button id="pubMode">Public Mode</button>

    <div id="container"></div>

    <script src="../script/frame.js"></script>
</body>

</html>

Js script.

frame.js

var frame = {
init: function(){
    //msg sender
    document.addEventListener('click', (event) => {
        var message = JSON.stringify({
            id: event.target.id
        });
        window.parent.postMessage(message, '*');
    });

    //msg reciever
    window.addEventListener('message', function (e) {
        document.getElementById('container').innerHTML = e.data;
    });
   
}}
document.addEventListener('DOMContentLoaded', frame.init);

popup.js

class popup{
   iframeMap = {
    'settingBtn': 'setting.html',
    'privMode': 'privMode.html',
    'pubMode': 'pubMode.html',
    'editBtn': 'edit.html'
   }

  constructor(){
    window.addEventListener('message', (e) => {
            let data = JSON.parse(e.data);
            let myPromise = new Promise((resolve, error) => {
                let frameObj = document.getElementById('bodyChange');
                frameObj.src = this.iframeMap[data.id];

                resolve(frameObj);
            }); 
           
            myPromise.then(frameObj => {
                console.log(frameObj.src);
                frameObj.contentWindow.postMessage(response, '*');
            });
           }
         });
       }
    }

   var obj = new popup();

Solution

  • You could use the iframe.onload event handler in your popup.js.

    popup.js

    class popup {
      iframeMap = {
        settingBtn: "setting.html",
        privMode: "privMode.html",
        pubMode: "pubMode.html",
        editBtn: "edit.html"
      };
      constructor() {
        window.addEventListener("message", (e) => {
          let data = JSON.parse(e.data);
          let frameObj = document.getElementById("bodyChange");
          frameObj.src = this.iframeMap[data.id];
          console.log(frameObj.src);
          frameObj.onload = () => {
            // TODO: replace frameObj.src with response
            frameObj.contentWindow.postMessage(frameObj.src, "*");
          };
        });
      }
    }
    
    var obj = new popup();
    

    I've created a CodeSandbox that demonstrate it.