4

I am trying to add a script block dynamically to the document. When I do this, the script block is not getting executed.

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

    <script type="text/javascript">
        var elem = document.getElementById("dynamicDiv");
        var tmpStr = "<script type=\"text\/javascript\"> ";
        tmpStr += "function hello (val)";
        tmpStr += "{";
        tmpStr += "alert('hello ' + val);";
        tmpStr += "}";
        tmpStr += "<\/script>";

        elem.innerHTML = tmpStr;

        hello("World");
    </script>
</body>

The above code does not work. From another post (How do you execute a dynamically loaded JavaScript block?), I saw a reply that if script is added to innerHTML, it will not be executed. Instead of directly using innerHTML, create a div with this innerHTML and use appendChild to add the script.

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

    <script type="text/javascript">
        var elem = document.getElementById("dynamicDiv");
        var tmpStr = "<script type=\"text\/javascript\"> ";
        tmpStr += "function hello (val)";
        tmpStr += "{";
        tmpStr += "alert('hello ' + val);";
        tmpStr += "}";
        tmpStr += "<\/script>";

        var newdiv = document.createElement('div');
        newdiv.innerHTML = tmpStr;

        elem.appendChild(newdiv);

        hello("World");
    </script>
</body>

How ever, this solution also did not work for me.

In another reply, I again saw that we should get the script elements and execute them using eval.

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

    <script type="text/javascript">
        var elem = document.getElementById("dynamicDiv");
        var tmpStr = "<script type=\"text\/javascript\"> ";
        tmpStr += "function hello (val)";
        tmpStr += "{";
        tmpStr += "alert('hello ' + val);";
        tmpStr += "}";
        tmpStr += "<\/script>";

        var newdiv = document.createElement('div');
        newdiv.innerHTML = tmpStr;

        elem.appendChild(newdiv);

        var scripts = newdiv.getElementsByTagName('script');
        for (var ix = 0; ix < scripts.length; ix++) {
            eval(scripts[ix].text);
        }

        hello("World");
    </script>
</body>

This solution works for me.

But if do this in a function then it does not work.

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

    <script type="text/javascript">

        function createFunction(){
            var elem = document.getElementById("dynamicDiv");
            var tmpStr = "<script type=\"text\/javascript\"> ";
            tmpStr += "function hello (val)";
            tmpStr += "{";
            tmpStr += "alert('hello ' + val);";
            tmpStr += "}";
            tmpStr += "<\/script>";

            var newdiv = document.createElement('div');
            newdiv.innerHTML = tmpStr;

            elem.appendChild(newdiv);

            var scripts = newdiv.getElementsByTagName('script');
            for (var ix = 0; ix < scripts.length; ix++) {
                eval(scripts[ix].text);
            }   
            hello("World 1");
        }

        createFunction();
        hello("World 2");
    </script>
</body>

I can see that the function is available after the script is evaled. and is available in the function createFunction. Outside createFunction() scope, hello() is not available.

What am I doing wrong? Am I missing something very basic? Please check and help.

Thanks, Paul

P.S. I don't use jQuery. I am using chrome to test this.

Community
  • 1
  • 1
Paul Nibin
  • 726
  • 3
  • 10
  • 18
  • You cannot add scripts dynamically inside the function .. – Prasath K Mar 22 '13 at 09:57
  • I tested your first code in `firefox` and it is working. – Rohan Kumar Mar 22 '13 at 09:58
  • @RohanKumar The third snippet works for me too, in the chrome as well as firefox. But fourth snippet does not work in both. The fourth snippet is supposed to do alert 2 times. "hello World 1" and "hello World 2". Somehow the hello function is not accessible outside the createFunction() scope. – Paul Nibin Mar 22 '13 at 11:12

2 Answers2

2

Would like to point out that the reason the 3rd snippet you provided works inside the for loop, but not outside is because you are using eval. eval takes a string and executes it as js, which is why it is working inside the loop, but using eval isn't parsing it for future use, which is causing it to be unusable elsewhere. Therefore, when you go to call it outside the loop, you get a reference error.

UPDATE:

If you are getting the string back with the <script> tags in it, you can just parse out the script tags.

var string = "<script type=\"text\/javascript\"> ";
    string += "function hello (val)";
    string += "{";
    string += "alert('hello ' + val);";
    string += "}";
    string += "<\/script>";
string = string.replace(/<(script|\/script).*?>/g,'');
function createFunction() {
    var elem = document.getElementById("dynamicDiv");
    var script = document.createElement('script');
    script.innerHTML = string;
    elem.appendChild(script);
    hello("World 1");
}
createFunction()
hello('world 2');

JSFiddle: http://jsfiddle.net/3wYD6/

I don't really see the point of this, but if you really want to do this you can create a new script element and then set it's innerHTML to the function, then append the new script to a div.

var elem = document.getElementById("dynamicDiv"),
    script = document.createElement('script');
script.innerHTML = 
    'function hello (val) {' +
        'alert("hello " + val);' + 
    '}';
elem.appendChild(script);
hello('world');
Jeff Shaver
  • 3,315
  • 18
  • 19
  • This test case works fine. But in my case, I will get the tempStr from external file. And the tempStr will contain both scripts and pcData. If I need to use the above soln, then I need to parse the string given to me to find the pcData and script blocks. Normal pcData, I can add to innerHTML and for scripts, I need to create script element Is there a simple way than parsing the tempStr? The third code snippet in the works fine for me. In this approach, I dont need to parse the tempString for pcData and script blocks. But when I make it into a func (as in the fourth snippet) it stops working. – Paul Nibin Mar 22 '13 at 11:08
  • Thanks Jeff for the updated answer. If my tmpStr is something like. var tmpStr = "I am a pcdata. I should not be added as a script."; tmpStr += " – Paul Nibin Mar 22 '13 at 13:41
  • @PaulNibin Updated fiddle: http://jsfiddle.net/3wYD6/1/ if all the scripts start with a function, you can use the regex in the fiddle. if not, you can use this line instead: `string = string.match(/>.*?)[0].replace('>','').replace('<','');` – Jeff Shaver Mar 22 '13 at 14:08
0

In your first try you are creating a string and js interpreter handle it as a string, not an html tag, so js doesn't really care about your script tags presented in that string.

Then of course it's working when you start using eval() because eval - is evil:))

After all you can create script tags dynamically and then fill it with code:

var elem = document.getElementById("dynamicDiv"),
    scriptTag = document.createElement('script'),
    scriptTagCode = 'function hello (val){alert("hello " + val);}';

scriptTag.innerHTML = scriptTagCode;
elem.appendChild(scriptTag);
hello('foo');
happyCoda
  • 418
  • 2
  • 2