0

I'm trying to embedd two html documents in another using javascript. The problem I am having is that the onload event does not fire on the embedded document.

paper.htm has several div tags and should contain curve.htm but in curve.htm the onload event is not firing

paper.htm

<html>
<head>
    <title>Curve</title>    
    <script>
        (function () {
            var xhr = new XMLHttpRequest();
            xhr.open('GET', 'curve.htm', true);
            xhr.onreadystatechange = function () {
                if (this.readyState !== 4) return;
                if (this.status !== 200) return;
                document.getElementById('chartBlock').innerHTML = this.responseText;
            }
            xhr.send();
        })();
    </script>
</head>
<body>
    <div id="paper">
        <div id="border">
            <div id="chartBlock"></div>
            <div id="titleBlock"></div>
        </div>
    </div>
</body>
</html>

curve.htm (partial)

<html>
<head>
    <script src="File:///Temp/curveData.js" type="text/javascript"></script>
    <script>
    window.onload = init; //this never fires!
    function init() { //... }
    </script>
<body>
    <canvas id="chartCanvas" width="954" height="625"></canvas>
</body>
</html> 

I have tried:

  1. Using jquery to load the html document (many examples here on SO).

  2. Putting onload in the body tag of the html document (curve.htm)

tried with jquery:

<script>
    $(function () {
        $("#chartBlock").load("curve.htm");
        $("#titleBlock").load("titleblock.htm");
    });
</script>

tried with html:

<body onload="init()">

Any other ideas to look into would be very much appreciated. Thanks

beeker
  • 780
  • 4
  • 17
  • Possible duplicate of [Executing – emerson.marini Jun 22 '16 at 18:28
  • A div is not a window, it can't contain `html`, `head` or `body` tag. Changing `innerHTML` of a div won't trigger `onload` on that div, no matter what is the added content. `onload` is fired only on elements which themselves load some external resources (like `img` and `iframe`). You could simply call `init` after setting `innerHTML` of the div. – Teemu Jun 22 '16 at 18:31

2 Answers2

1

Because the document will not be loaded...

What you are doing could be achieved with iframes. With an iframe, you are loading a full html document, which will be parsed as such. With the $.load function, you will just bluntly insert html, which will be parsed as <body>'s children. Meaning; the <head>, <meta> tags etc. will be ignored by all/proper browsers, because they should only occur inside the head of a document. Simplified, your output would be:

<html>
    <head>
        <!-- whatever -->
    </head>
    <body>

        <div id="chartBlock">
            <html>
                <!-- What?! Another html tag?! -->
            </html>
        </div>
        <div id="titleBlock">
            <html>
                <!-- And another one... -->
            </html>
        </div>

    </body>
</html>

So, what you want to do, is loading only the contents, what would be inside the <body> tag, and use the success callback of the $.load function to do whatever you want to do if the contents are inserted in your document.

giorgio
  • 10,111
  • 2
  • 28
  • 41
1

You could still load the page without using iframes, you just need to go about it a little differently. Basically since you're putting an html page inside of a div, the scripts on that page never get rendered.

To make it work, the scripts need to be inserted into the parent documents head.

Get scripts and insert them into head:

var head = document.getElementsByTagName('head')[0],
    script = document.createElement('script'),
    data;

script.type = 'text/javascript';

...

data = document.getElementById('chartBlock')
       .getElementsByTagName('script').item(0).innerHTML;

try {
  script.appendChild(document.createTextNode(data));      
} catch(e) {
  script.text = data;
}

head.insertBefore(script, head.firstChild);
head.removeChild(script);

Retrigger Load Event

var event = new Event('load');

//place after script has been inserted into head
window.dispatchEvent(event);

Using your example above:

curve.htm

<html>
   <head>
     <script src="File:///Temp/curveData.js"></script>
     <script>
        window.onload = init; //this will now fire
        function init() { alert('loaded'); }
     </script>
   </head>
   <body>
     <canvas id="chartCanvas" width="954" height="625"></canvas>
   </body>
</html> 

paper.htm

<html>
   <head>
     <title>Curve</title>
     <script>
        (function () {
           var xhr = new XMLHttpRequest(),
               event = new Event('load'),
               //since the onload event will have already been triggered
               //by the parent page we need to recreate it.
               //using a custom event would be best.
               head = document.getElementsByTagName('head')[0],
               script = document.createElement('script'),
               data;

           script.type = 'text/javascript';

           xhr.open('GET', 'curve.htm', true);
           xhr.onreadystatechange = function (){
               if (this.readyState !== 4) return;
               if (this.status !== 200) return;

               document.getElementById('chartBlock').innerHTML = this.responseText;

               data = document.getElementById('chartBlock')
                     .getElementsByTagName('script').item(0).innerHTML;
               //we're extracting the script containing the
               //onload handlers from curve.htm,
               //note that this will only cover the first script section..

               try {
                  // doesn't work on ie
                  script.appendChild(document.createTextNode(data));      
               } catch(e) {
                  script.text = data;
               }

               head.insertBefore(script, head.firstChild);
               head.removeChild(script);

               window.dispatchEvent(event);
               //once the scripts have been rendered,
               //we can trigger the onload event
           }
           xhr.send();
        })();
     </script>
   </head>
   <body>
     <div id="paper">
        <div id="border">
           <div id="chartBlock"></div>
           <div id="titleBlock"></div>
        </div>
     </div>
   </body>
</html>
Andrew
  • 569
  • 4
  • 5