innerHTML and SCRIPT tags

I have a requirement where I get some HTML snippet through Ajax request and then update a div area. So far so good. The HTML snippet needed to have some javascript (so that I could display a date as per the user’s timezone). That’s when the trouble started.

After a bit of research, came to the conclusion that

div.innerHTML = some-string-containing-script-tags;

doesn’t work. Some one mentioned about using <\/script> instead of </script> but that didn’t work for me though there was a reply to the suggestion that it worked! Then there is an interesting hack on how to achieve the same. While this is a cool hack, I didn’t wanted to do it.

So, by trail and error, in Firefox 2.0, it seemed to work by doing the following.

var div = document.createElement('div');
div.innerHTML = htmlFromAjaxResponse;
var children = div.childNodes;
actualDivToBeUpdated.innerHTML = "";
for(var i=0;i<children.length;i++)
actualDivToBeUpdated.appendChild(children[i]);

This worked in Firefox 2.0. The script in the original response HTML did get executed. (note though not to use document.write in the script. Instead, you have to manipulate the DOM).

The same technique didn’t work in IE though.

Update: As per microsoft making a script tag marked with DEFER attribute makes it possible to execute script by setting it through innerHTML. I tried and it worked. However, I now have the problem that the DOM node that’s inserted using the innerHTML doesn’t seem to be available by the time the script is executing even though the script is placed after the dom node.

Update 2: Finally got it working on both Firefox and IE. The problem with the DOM manipulation mentioned above is, in case of IE, after marking the script to DEFER, it is executed for the DIV element whose innerHTML is set. Since I am creating the DIV brand new, it’s not yet within the DOM, so trying to use getElementById in the script from the document is causing the problem. So, I had to introduce a dummy DIV element in the initial document and then it worked. However, for Firefox, the dummy element idea doesn’t work. It has to be a new element to create the DOM. Since that DOM is copied to the actual node as per the code shown above, at that time the script gets executed fine. So, I ended up writing browser specific code, but finally it seems to work for both browsers.

20 Comments

Filed under AJAX, DHTML, javascript

20 responses to “innerHTML and SCRIPT tags

  1. Steve

    In the wonderfully buggy world of IE, if you dynamically add a script tag to the DOM, you cannot do:

    //works in modern DOM aware browsers
    var scriptTag = document.createElement(‘script’);
    scriptTag.appendChild( document.createTextNode( ‘your js code here’ ) );

    //in IE, you can’t do the above (it will just ignore the code), you need to do:
    var scriptTag = document.createElement(‘script’);
    scriptTag.text = ‘your js code here’;

    Yet another ugly IE hack.

    PS in case you haven’t encountered it yet, you’ll find a similar issue when trying to create a style tag on the fly… 😦

  2. Firstname Lastname

    Cool. This works, except for the loop.

    You have

    for(var i=0;i 0) {
    var element = children[0];
    actualDivToBeUpdated.appendChild(element);
    }

    I’m on Mozilla 2.0.0.16.

    Anyway, none of this is yet working on IE. Before entering the loop, alert(tempChildNodes.length) shows there to be 1 node!

  3. Firstname Lastname

    Sorry, my post is missing a paragraph. What I found on Mozilla 2.0.0.16 is that

    actualDivToBeUpdated.appendChild(element);

    removes element from the children array. So what I had to do was the following:

    while (children.length > 0) {
    var element = children[0];
    actualDivToBeUpdated.appendChild(element);
    }

    Quite strange!

    But what I ended up doing is

    actualDivToBeUpdated.innerHTML = htmlFromAjaxResponse;
    var scripts = actualDivToBeUpdated.getElementsByTagName(“script”);
    var script = scripts[0];
    eval(script.text);

  4. S

    Hi, thanks for pointing out the issue with the array. I think Mozilla’s behavior is correct. A node can’t be under two parents in a DOM.

  5. T.G.

    Check this guy out. He’s got a much better solution for the same problem. After the innerHTML property is set he then walks the DOM of the element looking for script tags and executing them. Does it after load so you can refer to the content of the element you filled.

    http://brightbyte.de/page/Loading_script_tags_via_AJAX

  6. M.D.

    Prototype (and I’m sure other libraries) can handle this situation –

    http://www.prototypejs.org/api/element/insert

    – Mike

  7. Here is how I insert an Ajax response as javascript code in html:

    request.onreadystatechange = function(){
    if (request.readyState == 4) {
    var newScript = document.createElement(‘script’);
    newScript.type=’text/javascript’;
    newScript.text = request.responseText;
    document.getElementsByTagName(“head”)[0].appendChild(newScript);
    var body = document.getElementsByTagName(‘body’)[0];
    }
    }

  8. sorry, the body variable is not needed (last line).

  9. Everett

    One more thing I discovered is that if you return some HTML via ajax that has script tags in it, and do $(‘page_content’).innerHTML = responseText; then IE 7 will strip out some – but not all – of the script tags, so when you try to evaluate scripts on the innerHTML you’re missing some. My fix was to eval scripts on the responseText directly, using Prototype.js’s evalScripts method. (I’m not sure what technique they use, but I think they first call extractScripts and then eval on each one, which means they might be parsing the string, or they use the trick where you make a new div.)

    Any ideas why IE strips some script tags from the innerHTML? Any idea which ones will be stripped and which ones won’t be?

    Example:

    INNER HTML TEXT:

    Hello World
    alert(‘hi’);

    alert(‘hi’);

    RETURNED HTML:

    alert(‘hi’);alert(‘hi’);

    Hello World

    alert(‘hi’);alert(‘hi’);

  10. angelcn

    I want to know how to do if the contained no script but with the src that linking to the script outside like this:

  11. Pingback: innerHTML+ Javascript

  12. Hey T.G. thank you so much to share this:
    http://brightbyte.de/page/Loading_script_tags_via_AJAX
    (and a big thank you do brightbyte.de too)

    I was getting crazy trying to do the tag works with Ajax.

  13. Hey T.G. thank you so much to share this:
    http://brightbyte.de/page/Loading_script_tags_via_AJAX
    (and a big thank you to brightbyte.de too)

    I was getting crazy trying to do the tag works with Ajax.

  14. Here is a method that recursively replaces all scripts with executable ones:

    function replaceScriptsRecurse(node) {
    if ( nodeScriptIs(node) ) {
    var script = document.createElement(“script”);
    script.text = node.innerHTML;

    node.parentNode.replaceChild(script, node);
    }
    else {
    var i = 0;
    var children = node.childNodes;
    while ( i < children.length) {
    replaceScriptsRecurse( children[i] );
    i++;
    }
    }

    return node;
    }
    function nodeScriptIs(node) {
    return node.getAttribute && node.getAttribute("type") == "text/javascript";
    }

  15. Pingback: [Javascript] Executing elements inserted with .innerHTML - Pixorix

Leave a comment