Javascript script execution in innerHTML: the revenge

The execJS() I posted some time ago have some prob­lems (and it, yes, was just a modify to the AHAH ver­sion). I didn’t really real­ized what exactly it is, but I found a simple (?) solu­tion. The prob­lem, as far as I can under­stand, is that eval() doesn’t always exe­cute the code. So here it is the workaround: look for <script> tags, take its con­tent and create a new ele­ment into the <head> with createElement/appendChild. In this way we should also be more standard-​compliant than before:

function execJS(node)
{
  var bSaf = (navigator.userAgent.indexOf('Safari') != -1);
  var bOpera = (navigator.userAgent.indexOf('Opera') != -1);
  var bMoz = (navigator.appName == 'Netscape');

  if (!node) return;

  /* IE wants it uppercase */
  var st = node.getElementsByTagName('SCRIPT');
  var strExec;

  for(var i=0;i<st.length; i++)
  {
    if (bSaf) {
      strExec = st[i].innerHTML;
      st[i].innerHTML = "";
    } else if (bOpera) {
      strExec = st[i].text;
      st[i].text = "";
    } else if (bMoz) {
      strExec = st[i].textContent;
      st[i].textContent = "";
    } else {
      strExec = st[i].text;
      st[i].text = "";
    }

    try {
      var x = document.createElement("script");
      x.type = "text/javascript";

      /* In IE we must use .text! */
      if ((bSaf) || (bOpera) || (bMoz))
        x.innerHTML = strExec;
      else x.text = strExec;

      document.getElementsByTagName("head")[0].appendChild(x);
    } catch(e) {
      alert(e);
    }
  }
};

I tested it only under fire­fox, but it should work on other browsers too. If it doesn’t, let me know.

Update (Octo­ber 1st, 2006): now it works under Inter­net Explorer too (if you want to inject some text in a script ele­ment in IE you can’t use .inner­HTML, but you have to use .text!)

Leave a comment ?

30 Comments.

  1. is there anyway to exe­cute javascript that is loaded this way

    script type=”text/javascript” src=”something.js”

    instead of
    script type=”text/javascript”
    *all scripts here* /scripts

    with this execJS func­tion?

  2. Not exactly, you should modify the execJS() in order to look for src attrib­utes too and then pass the values to a func­tion like this:
    func­tion load_ext_script(url)
    {
    var x = doc​u​ment.createElement(“script”);
    x.src = url;
    x.type = “text/javascript”;
    doc​u​ment.getElementsByTagName(“head”)[0].appendChild(x);
    }
    I didn’t tested, but it should work.

  3. Doesn’t work in IE.

    IE doesn’t like .Inner­Html for the script object

    :(

  4. Oh, found a solu­tion.

    Use .text for IE!!!!

  5. You mean using “x.text” instead of “x.innerHTML” in the try block? (I have to refor­mat this post, the tran­si­tion from blogspot to word­press indented incor­rectly the code)

  6. The code doesnt work in IE. Can anyone who gets it work­ing in IE, pls post the changes made.

    Thanks

  7. I updated the script, now it should work under IE too… lemme know if some­thing doesn’t work

  8. From the entry:

    } else if (bMoz) {
    strExec = st[i].textContent;
    st[i].textContent; // !!!
    } else {

    Note that st[i].textContent is miss­ing the assign­ment.

    } else if (bMoz) {
    strExec = st[i].textContent;
    st[i].textContent = “”;
    } else {

    Thanks for the code.

  9. Uh, that’s what hap­pens when you write code at 4 AM :) Cor­rected now…

  10. var node = doc​u​ment.getElementById(node);

    /*
    little cor­rec­tion or else you get tihis error
    node.getEle­ments­By­Tag­Name is not a func­tion

    */

    if (!node) return;
    /* IE wants it upper­case */
    var st = node.getElementsByTagName(‘SCRIPT’);

  11. Easier solu­tion?
    func­tion execJS(node) {
    if (!node) return;
    var st = node.getElementsByTagName(‘SCRIPT’);
    for(var i=0;i

  12. “The prob­lem, as far as I can under­stand, is that eval() doesn’t always exe­cute the code.”

    Can a col­li­sion of vari­able names be the prob­lem?

    var st = [
    “for(var i=0; i<3; i++) alert(i);”,
    “alert(‘I do not get exe­cuted’)”
     ];

    for(var i=0;i<st.length; i++) {
    eval(st[i]);
     }

  13. It seems you solved your prob­lem by cre­at­ing a new ‘script’ ele­ment. But just out of curios­ity, do you get the prob­lem you get with the eval approach if you replace eval with the next func­tion?

    func­tion saferEval(__code__) {
    eval(__code__);
     }

  14. I didn’t tried, but I believe that it won’t work (and it’s not a col­li­sion of vari­able names). The prob­lem, as I real­ized some time after, is that the browser does NOT allow script exe­cu­tions loaded within the inner­HTML method due to secu­rity rea­sons.

  15. Thanks, works well! (In Fire­Fox anyway, and I hope IE too… will let you know if not)

  16. Just like andy­cjw I’m trying to use this script to load exter­nal *.js-​files. But I didn’t manage to solve this with the code you posted above. Could you explain it fur­ther or maybe con­tact me by e-mail? Thanks in advance! Like your script

  17. Neat script! Can I see some basic exam­ples of this? I’m trying to insert a div (with inner­HTML) with script tags in it that con­tains a func­tion that loads in an swf. The SWFOb­ject to be more exact http://​blog.​decon​cept.​com/​s​w​f​o​bject/. Is that pos­si­ble you think?

    Cheers

    Mike

  18. Mike…I’m also trying to get swfob­ject to work ie IE. But I didn’t suc­ceed yet. Did you?

    Cheers

    ‘The other’ Mike ;)

  19. Hi Kra­toruis,

    Thanks for a won­der­ful script. How­ever, could you help with how src=”something.js” can be man­aged?

  20. BTW, the script is not work­ing in IE. I tried alert(strExec) after:

    } else {
    strExec = st[i].text;

    but while it enters the loop (I checked), it prints an empty string.

  21. Okay, it works in IE. But there is a weird prob­lem - the inner­HTML cannot start with . I put some other HTML before that, and put the script later. Cheers!

  22. I guess some­thing got snipped out in my ear­lier com­ment due to being a tag - it should be, “the inner­HTML cannot start with <SCRIPT>

  23. uhm, I never noticed this behav­ior… Could you try if some­thing like x.innerHTML = “<span></span>” + strExec; works?

  24. This rocks. Works fairly well.

    Fol­lowup to com­ment 2 regard­ing how to deal with src = url javascript files:

    Down­side: if you’re refresh­ing the inner­HTML, you might be append­ing inner­HTML src’d javascript files to the doc­u­ment head mul­ti­ple times, lead­ing to pos­si­ble memory issues. You’ll want to check to see if you’ve already loaded a file via this method.

    Caught that using the DOM inspec­tor while watch­ing the page refresh.

  25. Hi.

    Thanks for the post. I found it after a few sec­onds of simple googling after I expe­ri­enced this prob­lem for a work related issue. The thing is, what exactly is the “node” vari­able? In other words, is there an exam­ple you can give as to how to run it? I have a DIV tag that I’d like to run it on and I am unsure if this is exactly what I want to do. Of course, I haven’t exper­i­mented with it yet, but maybe I’ve answered my own ques­tion. Either way, could you pro­vide an exam­ple? Keep up the good work!

  26. Ok, I got it to work in Fire­fox, but still no IE. I know it says “it doesn’t like inner­HTML!!!” but what do we need to change then? The func­tion itself pro­vided by this nice blog page or the actual javascript code where the DIV’s and SPAN’s are, etc, that have state­ments that change the inner­HTML of them?

  27. Ok, the prob­lem with IE not work­ing isn’t the .text or .inner­HTML con­fu­sion. It is the fact that: var st = node.getElementsByTagName(‘script’); doesn’t behave the same in Fire­fox as it does in IE. Every­time I get here in IE, it returns an array with st.length being 0 every­time. So in other words, the for loop is never even exe­cuted. Even trying to set DIV or SPAN or what­ever your node is with .text = ‘blah’ instead of .inner­HTML makes no dif­fer­ence.

  28. Ok, upon fur­ther inves­ti­ga­tion of my lead, some­one on IRC was kind enough to explain to me the cor­rect workaround to fix this annoy­ing IE issue:

    15:00:04 @makk | yeah, this is a known issue in IE
    15:00:08 @makk | there is a trick to get around it
    15:00:14 @makk | but i don’t rec­om­mend it
    15:00:32 @makk | all you have to do is put some non-​whitespace before the script tag
    15:00:42 @makk | and then you should be able to grab the ele­ment
    15:01:24 @makk | for exam­ple: div.inner­HTML = ’ …’;

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">

Trackbacks and Pingbacks: