For anyone still trying to do this, no, you can't inject a script using innerHTML , but it is possible to load a string into a script tag using a Blob and URL.
The innerHTML property is part of the Document Object Model (DOM) that allows Javascript code to manipulate a website being displayed. Specifically, it allows reading and replacing everything within a given DOM element (HTML tag).
The innerHTML property sets or returns the HTML content (inner HTML) of an element.
To execute JavaScript in a browser you have two options — either put it inside a script element anywhere inside an HTML document, or put it inside an external JavaScript file (with a . js extension) and then reference that file inside the HTML document using an empty script element with a src attribute.
Simplified ES6 version of @joshcomley's answer with an example.
No JQuery, No library, No eval, No DOM change, Just pure Javascript.
http://plnkr.co/edit/MMegiu?p=preview
var setInnerHTML = function(elm, html) {
elm.innerHTML = html;
Array.from(elm.querySelectorAll("script")).forEach( oldScript => {
const newScript = document.createElement("script");
Array.from(oldScript.attributes)
.forEach( attr => newScript.setAttribute(attr.name, attr.value) );
newScript.appendChild(document.createTextNode(oldScript.innerHTML));
oldScript.parentNode.replaceChild(newScript, oldScript);
});
}
Usage
$0.innerHTML = HTML; // does *NOT* run <script> tags in HTML
setInnerHTML($0, HTML); // does run <script> tags in HTML
@phidah... Here is a very interesting solution to your problem: http://24ways.org/2005/have-your-dom-and-script-it-too
So it would look like this instead:
<img src="empty.gif" onload="alert('test');this.parentNode.removeChild(this);" />
The OP's script doesn't work in IE 7. With help from SO, here's a script that does:
exec_body_scripts: function(body_el) {
// Finds and executes scripts in a newly added element's body.
// Needed since innerHTML does not run scripts.
//
// Argument body_el is an element in the dom.
function nodeName(elem, name) {
return elem.nodeName && elem.nodeName.toUpperCase() ===
name.toUpperCase();
};
function evalScript(elem) {
var data = (elem.text || elem.textContent || elem.innerHTML || "" ),
head = document.getElementsByTagName("head")[0] ||
document.documentElement,
script = document.createElement("script");
script.type = "text/javascript";
try {
// doesn't work on ie...
script.appendChild(document.createTextNode(data));
} catch(e) {
// IE has funky script nodes
script.text = data;
}
head.insertBefore(script, head.firstChild);
head.removeChild(script);
};
// main section of function
var scripts = [],
script,
children_nodes = body_el.childNodes,
child,
i;
for (i = 0; children_nodes[i]; i++) {
child = children_nodes[i];
if (nodeName(child, "script" ) &&
(!child.type || child.type.toLowerCase() === "text/javascript")) {
scripts.push(child);
}
}
for (i = 0; scripts[i]; i++) {
script = scripts[i];
if (script.parentNode) {script.parentNode.removeChild(script);}
evalScript(scripts[i]);
}
};
You should not use the innerHTML property but rather the appendChild method of the Node: a node in a document tree [HTML DOM]. This way you are able to later call your injected code.
Make sure that you understand that node.innerHTML is not the same as node.appendChild. You might want to spend some time on the Javascript Client Reference for more details and the DOM. Hope the following helps...
Sample injection works:
<!DOCTYPE HTML>
<html>
<head>
<title>test</title>
<script language="javascript" type="text/javascript">
function doOnLoad() {
addScript('inject',"function foo(){ alert('injected'); }");
}
function addScript(inject,code) {
var _in = document.getElementById('inject');
var scriptNode = document.createElement('script');
scriptNode.innerHTML = code;
_in.appendChild(scriptNode);
}
</script>
</head>
<body onload="doOnLoad();">
<div id="header">some content</div>
<div id="inject"></div>
<input type="button" onclick="foo(); return false;" value="Test Injected" />
</body>
</html>
regards
Here's a shorter, more efficient script that also works for scripts with the src property:
function insertAndExecute(id, text) {
document.getElementById(id).innerHTML = text;
var scripts = Array.prototype.slice.call(document.getElementById(id).getElementsByTagName("script"));
for (var i = 0; i < scripts.length; i++) {
if (scripts[i].src != "") {
var tag = document.createElement("script");
tag.src = scripts[i].src;
document.getElementsByTagName("head")[0].appendChild(tag);
}
else {
eval(scripts[i].innerHTML);
}
}
}
Note: whilst eval may cause a security vulnerability if not used properly, it is much faster than creating a script tag on the fly.
Try this snippet:
function stripAndExecuteScript(text) {
var scripts = '';
var cleaned = text.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){
scripts += arguments[1] + '\n';
return '';
});
if (window.execScript){
window.execScript(scripts);
} else {
var head = document.getElementsByTagName('head')[0];
var scriptElement = document.createElement('script');
scriptElement.setAttribute('type', 'text/javascript');
scriptElement.innerText = scripts;
head.appendChild(scriptElement);
head.removeChild(scriptElement);
}
return cleaned;
};
var scriptString = '<scrip' + 't + type="text/javascript">alert(\'test\');</scr' + 'ipt><strong>test</strong>';
document.getElementById('element').innerHTML = stripAndExecuteScript(scriptString);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With