Cody Cook Cody Cook - 4 months ago 19
HTML Question

Sending a chunk of HTML to another URL using postMessage()

Objective: Copy a chunk of HTML and send it to a website on another domain.

My problem: The website I'm working on and the website in the iframe are on different domains. I own both of them and have set the Access-Control-Allow-Origin to allow the websites to communicate to each other. However, I can't seem to pass the HTML chunk to the parent window.

I've tried

parent.window.postMessage(chunk, http://www.parent-page.com)
(chunk is the chunk of HTML code) but I get this error:

Uncaught DataCloneError: Failed to execute 'postMessage' on 'Window': An object could not be cloned.


I have also tried to use ajax to send a PUT request to the parent window but, I get a 404 error that it cannot find the parent window. *I am running the parent window from my local server.



My Question: Can anyone tell me the best way to send an object, containing HTML code, from an iframe to the parent window given that the two websites are NOT on the same domain?

EDIT: I removed the stuff about a skeleton object as that was out of the scope of the question I was really trying to ask.

Answer

Here is what I wrote to solve this. Any constructive criticism is welcome.

Code on parent window's website:

//send a message to the website in the iframe
  $("#frame").on("load", function (event) {
    var viewContainer = $('#element-highlight');
    var iframe = document.querySelector('iframe');
    var receiver = iframe.contentWindow;
    var location = 'http://www.child-website.com';
    event.preventDefault();
    receiver.postMessage("sendStructure",location);		 
  });

//listen for a response
  window.addEventListener('message', function(event) { //event = onmessage event object
    if (~event.origin.indexOf('http://ccook.oegllc.com')) { //indexOf returns a -1 if the searchValue is not found 	  
  		  var structure = event.data;
		  var container = document.getElementById("element-highlight");
		  container.innerHTML = structure;
    }
  }
<script src="../jquery/3.0.0/jquery.min.js"></script>
<body>
  <div id="frame-container">
        <iframe id="frame" src="http://www.main-site.com" frameborder="0"></iframe>
        <div id="element-highlight">
          <!-- Store Skeleton Copies here -->
        </div>
</div>
  
</body>

Code on the website that is shown in the iframe:

I can't get the case statement below to look any better.

        //listen for command from main-site.com
        window.addEventListener('message', function(event) { //event = onmessage event object
            if (~event.origin.indexOf('http://www.main-site.com')) { //indexOf returns a -1 if the searchValue is not found
                switch(event.data){
                    case "sendStructure":
	                  var structure = getStructure(),
                      tempNode = document.createElement("div");
                      structure.appendTo(tempNode); //appends structure to html document
					  var str = tempNode.innerHTML; //creates a serilized version of the structure
					  parent.window.postMessage(str, event.origin); //send structure string to main-site.com
					break;
    //I reccomend using a case statement if the two sites will be sending more than one message to each other
                    default:
                        sendError();
                }
            }

        });


        function getStructure(){
            //this method creates a skeleton of the course page you are on
            //returns a skeleton object
            console.log("compiling structure");
            var viewFrame = $('body').contents(); //<-change 'body' to whatever element you want to copy
            var visible = viewFrame.find('*:not(html body)').filter(':visible');
            var overlayElements = visible.map(function (i, el) {
                    var el = $(el);
                    var overlayEl = $('<div>');

                    overlayEl.addClass('highlight').css($.extend({
                        position: 'absolute',
                        width: el.outerWidth(),
                        height: el.outerHeight(),
                        'z-index': el.css('z-index')
                    }, el.offset()));

                return overlayEl.get();
                });
          
        return overlayElements;
        }

        function sendError(){
            console.log("main-website's request could not be understood");
        }