0

PROBLEM:

Why does this not show the alert? And how can I make it so?

<script>
    function onSuccess() {
        var response= "<script> alert(1);</\script>";
        document.getElementById("xxx").innerHTML = response;
    }
</script>
<div id="xxx">existing text</div>
<button id="click" onclick="onSuccess();">click</button>

http://jsfiddle.net/7hWRR/1/

This is just a simplified version of my problem. In our application (in one very old module in particular) we use an ancient home-grown AJAX class which just innerHTMLs all AJAX responses.Traditionally we have only sent back HTML as AJAX response but I would like to execute JS in the success handler.I do not have access to the JS file so cannot modify the way the response is handled. I can only work with the fact that the success handler calls div.innerHTML='<my response>'

So stupid as it may be, I'm hoping for some help using these constraints!

SIMILAR LINKS:

Dynamically adding script element to a div does not execute the script

Dynamically added script will not execute

Community
  • 1
  • 1
Sajjan Sarkar
  • 3,900
  • 5
  • 40
  • 51
  • 1
    I think sometimes is worth going through the social trouble to get that JS file than to fix a broken system. – elclanrs Nov 11 '13 at 22:51
  • Are you willing to use jQuery? Its `.load()` method scans the returned HTML for ` – Barmar Nov 11 '13 at 23:04
  • If you can't change the fact that the handler just sets `.innerHTML` then you're SOL. That mechanism will simply never execute a script, it's not how it works. Wasn't that clear from the questions you linked to? – Barmar Nov 11 '13 at 23:06
  • Is the div always the same? – Renato Zannon Nov 11 '13 at 23:07
  • @Barmar I knew about jQuery load() but unfortunately we cant use it. And yes it seemed pretty clear that innerHTML cant execute scripts, but was hoping against hope! Thank you though. – Sajjan Sarkar Nov 12 '13 at 14:26

1 Answers1

1

Caveat: Here I'm assuming the <div> on which the results are inserted is known.

A possible solution is to use a MutationObserver (and the DOMNodeInserted event, to support IE 9 and 10) to watch said <div> for changes on its contents, and execute the code on any inserted <script> tags.

Example built upon your jsFiddle:

watchNodeForScripts(document.getElementById("xxx"));

function watchNodeForScripts(scriptRecipient) {
  if ('MutationObserver' in window) {
    // Prefer MutationObserver: https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
    watchUsingMutationObserver();
  } else {
    // Fallback to Mutation Events: https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Events/Mutation_events
    watchUsingDeprecatedMutationEvents();
  }

  function watchUsingMutationObserver() {
    var observer = new MutationObserver(function (mutations) {
      mutations.forEach(function (mutation) {
        var i, addedNodes = mutation.addedNodes;

        for (i = 0; i < addedNodes.length; i++) {
          handleAddedNode(addedNodes[i]);
        }
      });
    });

    observer.observe(scriptRecipient, {
      childList: true
    });
  }

  function watchUsingDeprecatedMutationEvents() {
    scriptRecipient.addEventListener("DOMNodeInserted", function (event) {
      handleAddedNode(event.target);
    });
  }

  function handleAddedNode(node) {
    // Don't try to execute non-script elements
    if (!(node instanceof HTMLScriptElement)) return;

    // Don't try to execute linked scripts
    if (node.src !== "") return;

    // Use 'new Function' instead of eval to avoid
    // the creation of a (undesired) closure
    fn = new Function(node.textContent);
    fn.call(window);
  }
}

Updated fiddle: http://jsfiddle.net/7hWRR/13/

Edit: Changed innerText to the more cross-compatible textContent.

Edit2: Don't execute code that isn't inside a <script> element.

Edit3: Don't execute scripts with the src attribute, and add mutation events fallback

Renato Zannon
  • 28,805
  • 6
  • 38
  • 42
  • That's a pretty cool way of doing it,I had never heard of MutationObserver before, read up on it now..This example didnt work on chrome for me though.. No error ,just didnt show the alert. – Sajjan Sarkar Nov 12 '13 at 14:29
  • Weird, I use chrome and it executed just fine for me... Which version are you on? – Renato Zannon Nov 12 '13 at 14:40
  • @SajjanSarkar I've just made a change. Can you test it out again? – Renato Zannon Nov 12 '13 at 15:39
  • worked, perfect! also thanks for the informative edit comment. – Sajjan Sarkar Nov 12 '13 at 18:17
  • @SajjanSarkar great :) Just be sure to take a look at [MutationEvents](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Events/Mutation_events) too, because you will need to fallback to them if you need to support IE < 11. MutationObserver is a relatively new API, and no IE before 11 has it. – Renato Zannon Nov 12 '13 at 18:50
  • @SajjanSarkar I don't know if you get notifications for edited answers, so I'm pinging you: I've made some changes to support IE 9 and 10, you might want to check it out. – Renato Zannon Nov 13 '13 at 18:32
  • 1
    that's fantastic..I was wondering why u were using new Function() instead of eval(), i get it now after seeing ur comment.Also love the way u've thought of linked scripts (though i cant believe someone would append a JS file reference to an Element,well, unless its the head ur watching).. very cool code man.. i would double accept it if I could :( ! – Sajjan Sarkar Nov 13 '13 at 22:38