[ACCEPTED]-How do you execute a dynamically loaded JavaScript block?-ajax

Accepted answer
Score: 18

Script added by setting the innerHTML property 3 of an element doesn't get executed. Try 2 creating a new div, setting its innerHTML, then 1 adding this new div to the DOM. For example:

<html>
<head>
<script type='text/javascript'>
function addScript()
{
    var str = "<script>alert('i am here');<\/script>";
    var newdiv = document.createElement('div');
    newdiv.innerHTML = str;
    document.getElementById('target').appendChild(newdiv);
}
</script>
</head>
<body>
<input type="button" value="add script" onclick="addScript()"/>
<div>hello world</div>
<div id="target"></div>
</body>
</html>
Score: 15

You don't have to use regex if you are using 2 the response to fill a div or something. You 1 can use getElementsByTagName.

div.innerHTML = response;
var scripts = div.getElementsByTagName('script');
for (var ix = 0; ix < scripts.length; ix++) {
    eval(scripts[ix].text);
}
Score: 9

While the accepted answer from @Ed. does 11 not work on current versions of Firefox, Google 10 Chrome or Safari browsers I managed to adept 9 his example in order to invoke dynamically 8 added scripts.

The necessary changes are 7 only in the way scripts are added to DOM. Instead 6 of adding it as innerHTML the trick was to create 5 a new script element and add the actual 4 script content as innerHTML to the created element 3 and then append the script element to the 2 actual target.

<html>
<head>
<script type='text/javascript'>
function addScript()
{
    var newdiv = document.createElement('div');

    var p = document.createElement('p');
    p.innerHTML = "Dynamically added text";
    newdiv.appendChild(p);

    var script = document.createElement('script');
    script.innerHTML = "alert('i am here');";
    newdiv.appendChild(script);

    document.getElementById('target').appendChild(newdiv);
}
</script>
</head>
<body>
<input type="button" value="add script" onclick="addScript()"/>
<div>hello world</div>
<div id="target"></div>
</body>
</html>

This works for me on Firefox 1 42, Google Chrome 48 and Safari 9.0.3

Score: 3

An alternative is to not just dump the return 8 from the Ajax call into the DOM using InnerHTML.

You 7 can insert each node dynamically, and then 6 the script will run.

Otherwise, the browser 5 just assumes you are inserting a text node, and 4 ignores the scripts.

Using Eval is rather 3 evil, because it requires another instance 2 of the Javascript VM to be fired up and 1 JIT the passed string.

Score: 1

The best method would probably be to identify 6 and eval the contents of the script block 5 directly via the DOM.

I would be careful 4 though.. if you are implementing this to 3 overcome a limitation of some off site call 2 you are opening up a security hole.

Whatever 1 you implement could be exploited for XSS.

Score: 0

You can use one of the popular Ajax libraries 3 that do this for you natively. I like Prototype. You 2 can just add evalScripts:true as part of 1 your Ajax call and it happens automagically.

Score: 0

For those who like to live dangerously:

// This is the HTML with script element(s) we want to inject
var newHtml = '<b>After!</b>\r\n<' +
  'script>\r\nchangeColorEverySecond();\r\n</' +
  'script>';
  
// Here, we separate the script tags from the non-script HTML
var parts = separateScriptElementsFromHtml(newHtml);

function separateScriptElementsFromHtml(fullHtmlString) {
    var inner = [], outer = [], m;
    while (m = /<script>([^<]*)<\/script>/gi.exec(fullHtmlString)) {
        outer.push(fullHtmlString.substr(0, m.index));
        inner.push(m[1]);
        fullHtmlString = fullHtmlString.substr(m.index + m[0].length);
    }
    outer.push(fullHtmlString);
    return {
        html: outer.join('\r\n'),
        js: inner.join('\r\n')
    };
}

// In 2 seconds, inject the new HTML, and run the JS
setTimeout(function(){
  document.getElementsByTagName('P')[0].innerHTML = parts.html;
  eval(parts.js);
}, 2000);


// This is the function inside the script tag
function changeColorEverySecond() {
  document.getElementsByTagName('p')[0].style.color = getRandomColor();
  setTimeout(changeColorEverySecond, 1000);
}

// Here is a fun fun function copied from:
// https://stackoverflow.com/a/1484514/2413712
function getRandomColor() {
  var letters = '0123456789ABCDEF';
  var color = '#';
  for (var i = 0; i < 6; i++) {
    color += letters[Math.floor(Math.random() * 16)];
  }
  return color;
}
<p>Before</p>

0

More Related questions