Javascript script execution in innerHTML: the revenge
March 7th, 2006
The execJS() I posted some time ago have some problems (and it, yes, was just a modify to the AHAH version). I didn’t really realized what exactly it is, but I found a simple (?) solution. The problem, as far as I can understand, is that eval() doesn’t always execute the code. So here it is the workaround: look for <script> tags, take its content and create a new element into the <head> with createElement/appendChild. In this way we should also be more standard-compliant than before:
function execJS(node)
{
var bSaf = (navigator.userAgent.indexOf('Safari') != -1);
var bOpera = (navigator.userAgent.indexOf('Opera') != -1);
var bMoz = (navigator.appName == 'Netscape');
if (!node) return;
/* IE wants it uppercase */
var st = node.getElementsByTagName('SCRIPT');
var strExec;
for(var i=0;i<st.length; i++)
{
if (bSaf) {
strExec = st[i].innerHTML;
st[i].innerHTML = "";
} else if (bOpera) {
strExec = st[i].text;
st[i].text = "";
} else if (bMoz) {
strExec = st[i].textContent;
st[i].textContent = "";
} else {
strExec = st[i].text;
st[i].text = "";
}
try {
var x = document.createElement("script");
x.type = "text/javascript";
/* In IE we must use .text! */
if ((bSaf) || (bOpera) || (bMoz))
x.innerHTML = strExec;
else x.text = strExec;
document.getElementsByTagName("head")[0].appendChild(x);
} catch(e) {
alert(e);
}
}
};
I tested it only under firefox, but it should work on other browsers too. If it doesn’t, let me know.
Update (October 1st, 2006): now it works under Internet Explorer too (if you want to inject some text in a script element in IE you can’t use .innerHTML, but you have to use .text!)
is there anyway to execute javascript that is loaded this way
script type=”text/javascript” src=”something.js”
instead of
script type=”text/javascript”
*all scripts here* /scripts
with this execJS function?
Comment by andycjw — March 26th, 2006 at 23:14
Not exactly, you should modify the execJS() in order to look for src attributes too and then pass the values to a function like this:
function load_ext_script(url)
{
var x = document.createElement(“script”);
x.src = url;
x.type = “text/javascript”;
document.getElementsByTagName(“head”)[0].appendChild(x);
}
I didn’t tested, but it should work.
Comment by kratorius — March 27th, 2006 at 11:53
Doesn’t work in IE.
IE doesn’t like .InnerHtml for the script object
:(
Comment by blah — September 26th, 2006 at 18:24
Oh, found a solution.
Use .text for IE!!!!
Comment by blah — September 26th, 2006 at 21:05
You mean using “x.text” instead of “x.innerHTML” in the try block? (I have to reformat this post, the transition from blogspot to wordpress indented incorrectly the code)
Comment by kratorius — September 26th, 2006 at 21:13
The code doesnt work in IE. Can anyone who gets it working in IE, pls post the changes made.
Thanks
Comment by Marz — September 27th, 2006 at 12:20
I updated the script, now it should work under IE too… lemme know if something doesn’t work
Comment by kratorius — October 1st, 2006 at 18:48
From the entry:
} else if (bMoz) {
strExec = st[i].textContent;
st[i].textContent; // !!!
} else {
Note that st[i].textContent is missing the assignment.
} else if (bMoz) {
strExec = st[i].textContent;
st[i].textContent = “”;
} else {
Thanks for the code.
Comment by zellster — October 27th, 2006 at 19:48
Uh, that’s what happens when you write code at 4 AM :) Corrected now…
Comment by kratorius — October 27th, 2006 at 20:29
var node = document.getElementById(node);
/*
little correction or else you get tihis error
node.getElementsByTagName is not a function
*/
if (!node) return;
/* IE wants it uppercase */
var st = node.getElementsByTagName(‘SCRIPT’);
Comment by cherijs — February 5th, 2007 at 23:10
Easier solution?
function execJS(node) {
if (!node) return;
var st = node.getElementsByTagName(‘SCRIPT’);
for(var i=0;i
Comment by Hao W — February 7th, 2007 at 20:20
“The problem, as far as I can understand, is that eval() doesn’t always execute the code.”
Can a collision of variable names be the problem?
var st = [
“for(var i=0; i<3; i++) alert(i);”,
“alert(‘I do not get executed’)”
];
for(var i=0;i<st.length; i++) {
eval(st[i]);
}
Comment by myavuzselim — April 15th, 2007 at 3:17
It seems you solved your problem by creating a new ‘script’ element. But just out of curiosity, do you get the problem you get with the eval approach if you replace eval with the next function?
function saferEval(__code__) {
eval(__code__);
}
Comment by myavuzselim — April 15th, 2007 at 4:00
I didn’t tried, but I believe that it won’t work (and it’s not a collision of variable names). The problem, as I realized some time after, is that the browser does NOT allow script executions loaded within the innerHTML method due to security reasons.
Comment by kratorius — April 22nd, 2007 at 17:16
Thanks, works well! (In FireFox anyway, and I hope IE too… will let you know if not)
Comment by Brian Birtle — May 5th, 2007 at 15:46
[…] May 27th, 2007 More than one year ago I was playing with AJAX, and I was facing a problem with scripts contained in documents loaded through XMLHttpRequest. So, at that time, I wrote two blog posts talking about this issue. The first was just a modify to the well known AHAH technique, while the second post was a script I entirely wrote by myself: “Javascript script execution in innerHTML: the revenge“. […]
Pingback by Javascript script execution in innerHTML: another round « kratorius::code — May 27th, 2007 at 17:20
Just like andycjw I’m trying to use this script to load external *.js-files. But I didn’t manage to solve this with the code you posted above. Could you explain it further or maybe contact me by e-mail? Thanks in advance! Like your script
Comment by Mike — May 30th, 2007 at 21:54
Neat script! Can I see some basic examples of this? I’m trying to insert a div (with innerHTML) with script tags in it that contains a function that loads in an swf. The SWFObject to be more exact http://blog.deconcept.com/swfobject/. Is that possible you think?
Cheers
Mike
Comment by mike — May 31st, 2007 at 8:22
hi,
I actually got this working… works ok in Safari and FF, but doesn’t seem to work in IE. Any suggestions?
http://catfish.businesscatalyst.com/CatalogueRetrieve.aspx?CatalogueID=8269&ProductID=132786
Cheers
mike
Comment by mike — May 31st, 2007 at 9:10
Mike…I’m also trying to get swfobject to work ie IE. But I didn’t succeed yet. Did you?
Cheers
‘The other’ Mike ;)
Comment by Mike — June 3rd, 2007 at 22:34
Hi Kratoruis,
Thanks for a wonderful script. However, could you help with how src=”something.js” can be managed?
Comment by Kishore — August 6th, 2007 at 7:54
BTW, the script is not working in IE. I tried alert(strExec) after:
} else {
strExec = st[i].text;
but while it enters the loop (I checked), it prints an empty string.
Comment by Kishore — August 6th, 2007 at 8:18
Okay, it works in IE. But there is a weird problem - the innerHTML cannot start with . I put some other HTML before that, and put the script later. Cheers!
Comment by Kishore — August 6th, 2007 at 8:23
I guess something got snipped out in my earlier comment due to being a tag - it should be, “the innerHTML cannot start with <SCRIPT>
Comment by Kishore — August 6th, 2007 at 8:24
uhm, I never noticed this behavior… Could you try if something like x.innerHTML = “<span></span>” + strExec; works?
Comment by kratorius — August 6th, 2007 at 19:59
This rocks. Works fairly well.
Followup to comment 2 regarding how to deal with src = url javascript files:
Downside: if you’re refreshing the innerHTML, you might be appending innerHTML src’d javascript files to the document head multiple times, leading to possible memory issues. You’ll want to check to see if you’ve already loaded a file via this method.
Caught that using the DOM inspector while watching the page refresh.
Comment by don — August 29th, 2008 at 6:32
Hi.
Thanks for the post. I found it after a few seconds of simple googling after I experienced this problem for a work related issue. The thing is, what exactly is the “node” variable? In other words, is there an example you can give as to how to run it? I have a DIV tag that I’d like to run it on and I am unsure if this is exactly what I want to do. Of course, I haven’t experimented with it yet, but maybe I’ve answered my own question. Either way, could you provide an example? Keep up the good work!
Comment by smu johnson — November 28th, 2009 at 3:52
Ok, I got it to work in Firefox, but still no IE. I know it says “it doesn’t like innerHTML!!!” but what do we need to change then? The function itself provided by this nice blog page or the actual javascript code where the DIV’s and SPAN’s are, etc, that have statements that change the innerHTML of them?
Comment by smu johnson — November 30th, 2009 at 23:27
Ok, the problem with IE not working isn’t the .text or .innerHTML confusion. It is the fact that: var st = node.getElementsByTagName(‘script’); doesn’t behave the same in Firefox as it does in IE. Everytime I get here in IE, it returns an array with st.length being 0 everytime. So in other words, the for loop is never even executed. Even trying to set DIV or SPAN or whatever your node is with .text = ‘blah’ instead of .innerHTML makes no difference.
Comment by smu johnson — December 1st, 2009 at 0:12
Ok, upon further investigation of my lead, someone on IRC was kind enough to explain to me the correct workaround to fix this annoying IE issue:
15:00:04 @makk | yeah, this is a known issue in IE
15:00:08 @makk | there is a trick to get around it
15:00:14 @makk | but i don’t recommend it
15:00:32 @makk | all you have to do is put some non-whitespace before the script tag
15:00:42 @makk | and then you should be able to grab the element
15:01:24 @makk | for example: div.innerHTML = ’ …’;
Comment by smu johnson — December 1st, 2009 at 1:14