I have a requirement where I get some HTML snippet through Ajax request and then update a div area. So far so good. The HTML snippet needed to have some javascript (so that I could display a date as per the user’s timezone). That’s when the trouble started.
After a bit of research, came to the conclusion that
div.innerHTML = some-string-containing-script-tags;
doesn’t work. Some one mentioned about using <\/script> instead of </script> but that didn’t work for me though there was a reply to the suggestion that it worked! Then there is an interesting hack on how to achieve the same. While this is a cool hack, I didn’t wanted to do it.
So, by trail and error, in Firefox 2.0, it seemed to work by doing the following.
var div = document.createElement('div');
div.innerHTML = htmlFromAjaxResponse;
var children = div.childNodes;
actualDivToBeUpdated.innerHTML = "";
for(var i=0;i<children.length;i++)
actualDivToBeUpdated.appendChild(children[i]);
This worked in Firefox 2.0. The script in the original response HTML did get executed. (note though not to use document.write in the script. Instead, you have to manipulate the DOM).
The same technique didn’t work in IE though.
Update: As per microsoft making a script tag marked with DEFER attribute makes it possible to execute script by setting it through innerHTML. I tried and it worked. However, I now have the problem that the DOM node that’s inserted using the innerHTML doesn’t seem to be available by the time the script is executing even though the script is placed after the dom node.
Update 2: Finally got it working on both Firefox and IE. The problem with the DOM manipulation mentioned above is, in case of IE, after marking the script to DEFER, it is executed for the DIV element whose innerHTML is set. Since I am creating the DIV brand new, it’s not yet within the DOM, so trying to use getElementById in the script from the document is causing the problem. So, I had to introduce a dummy DIV element in the initial document and then it worked. However, for Firefox, the dummy element idea doesn’t work. It has to be a new element to create the DOM. Since that DOM is copied to the actual node as per the code shown above, at that time the script gets executed fine. So, I ended up writing browser specific code, but finally it seems to work for both browsers.
In the wonderfully buggy world of IE, if you dynamically add a script tag to the DOM, you cannot do:
//works in modern DOM aware browsers
var scriptTag = document.createElement(‘script’);
scriptTag.appendChild( document.createTextNode( ‘your js code here’ ) );
//in IE, you can’t do the above (it will just ignore the code), you need to do:
var scriptTag = document.createElement(‘script’);
scriptTag.text = ‘your js code here’;
Yet another ugly IE hack.
PS in case you haven’t encountered it yet, you’ll find a similar issue when trying to create a style tag on the fly… 😦
“scriptTag.text” every browser ALL right! Thinks!
More solutions here: http://nerd.metrocat.org/2006/07/going-global
dead link
Cool. This works, except for the loop.
You have
for(var i=0;i 0) {
var element = children[0];
actualDivToBeUpdated.appendChild(element);
}
I’m on Mozilla 2.0.0.16.
Anyway, none of this is yet working on IE. Before entering the loop, alert(tempChildNodes.length) shows there to be 1 node!
Sorry, my post is missing a paragraph. What I found on Mozilla 2.0.0.16 is that
actualDivToBeUpdated.appendChild(element);
removes element from the children array. So what I had to do was the following:
while (children.length > 0) {
var element = children[0];
actualDivToBeUpdated.appendChild(element);
}
Quite strange!
But what I ended up doing is
actualDivToBeUpdated.innerHTML = htmlFromAjaxResponse;
var scripts = actualDivToBeUpdated.getElementsByTagName(“script”);
var script = scripts[0];
eval(script.text);
Hi, thanks for pointing out the issue with the array. I think Mozilla’s behavior is correct. A node can’t be under two parents in a DOM.
Check this guy out. He’s got a much better solution for the same problem. After the innerHTML property is set he then walks the DOM of the element looking for script tags and executing them. Does it after load so you can refer to the content of the element you filled.
http://brightbyte.de/page/Loading_script_tags_via_AJAX
or didnt work for me …
But Yes i “like” this page :
http://brightbyte.de/page/Loading_script_tags_via_AJAX
The above worked like a charm . Really served my purpose . Surely try this out .
Prototype (and I’m sure other libraries) can handle this situation –
http://www.prototypejs.org/api/element/insert
– Mike
Here is how I insert an Ajax response as javascript code in html:
request.onreadystatechange = function(){
if (request.readyState == 4) {
var newScript = document.createElement(‘script’);
newScript.type=’text/javascript’;
newScript.text = request.responseText;
document.getElementsByTagName(“head”)[0].appendChild(newScript);
var body = document.getElementsByTagName(‘body’)[0];
}
}
sorry, the body variable is not needed (last line).
One more thing I discovered is that if you return some HTML via ajax that has script tags in it, and do $(‘page_content’).innerHTML = responseText; then IE 7 will strip out some – but not all – of the script tags, so when you try to evaluate scripts on the innerHTML you’re missing some. My fix was to eval scripts on the responseText directly, using Prototype.js’s evalScripts method. (I’m not sure what technique they use, but I think they first call extractScripts and then eval on each one, which means they might be parsing the string, or they use the trick where you make a new div.)
Any ideas why IE strips some script tags from the innerHTML? Any idea which ones will be stripped and which ones won’t be?
Example:
INNER HTML TEXT:
…
Hello World
alert(‘hi’);
alert(‘hi’);
…
RETURNED HTML:
…
alert(‘hi’);alert(‘hi’);
Hello World
alert(‘hi’);alert(‘hi’);
…
Check for How to inject NoScope elements into a page with innerHTML on this link
http://msdn.microsoft.com/en-us/library/ms533897%28VS.85%29.aspx
I want to know how to do if the contained no script but with the src that linking to the script outside like this:
Pingback: innerHTML+ Javascript
Hey T.G. thank you so much to share this:
http://brightbyte.de/page/Loading_script_tags_via_AJAX
(and a big thank you do brightbyte.de too)
I was getting crazy trying to do the tag works with Ajax.
Hey T.G. thank you so much to share this:
http://brightbyte.de/page/Loading_script_tags_via_AJAX
(and a big thank you to brightbyte.de too)
I was getting crazy trying to do the tag works with Ajax.
Here is a method that recursively replaces all scripts with executable ones:
function replaceScriptsRecurse(node) {
if ( nodeScriptIs(node) ) {
var script = document.createElement(“script”);
script.text = node.innerHTML;
node.parentNode.replaceChild(script, node);
}
else {
var i = 0;
var children = node.childNodes;
while ( i < children.length) {
replaceScriptsRecurse( children[i] );
i++;
}
}
return node;
}
function nodeScriptIs(node) {
return node.getAttribute && node.getAttribute("type") == "text/javascript";
}
Pingback: [Javascript] Executing elements inserted with .innerHTML - Pixorix