Reputation: 4198
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>
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
Upvotes: 0
Views: 334
Reputation: 29941
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
Upvotes: 1