So this is our scenario... First thing we do is, we append a piece of javascript code which adds external script to document like this:
(function() {
var e = document.createElement('script'); e.type = 'text/javascript'; e.async = true; e.src = 'http://blabla.com/script.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(e, s);
})();
Then in script.js
following happens:
function ajaxCall() {
//... some script to send ajax request which calls createDiv() after success
if (window.XMLHttpRequest){
xmlhttp=new XMLHttpRequest();
}
else{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function(){
if(xmlhttp.readyState==4&&xmlhttp.status==200){
createDiv(xmlhttp.responseText);
}
};
xmlhttp.open("GET","http://blabla.com/api/");
xmlhttp.send();
}
function parseResponse(response) {
var parser = new DOMParser();
var dom = parser.parseFromString(response, "text/html");
return dom;
}
function createDiv(responsetext)
{
var dom = parseResponse(responsetext);
var _ws = dom.getElementById('styles');
var h = document.getElementsByTagName('head')[0];
h.appendChild(document.importNode(_ws, true));
var _jr = dom.getElementById('script1').outerHTML;
var _vc = dom.getElementById('script2').outerHTML;
var _rv = dom.getElementById('script3').outerHTML;
var _rw = dom.getElementById('my_div');
var _b = document.getElementsByTagName('body')[0];
var _d = document.createElement('div'); _d.id = 'just_id';
_d.innerHTML = _jr + _vc + _rv;
_d.appendChild(document.importNode(_rw, true));
_b.appendChild(_d);
}
ajaxCall();
Everything works fine, script's and a div are being appended as expected and where expected, but appended script doesn't get executed and doesn't affect appended div. Why is that? And how can I make it execute? We also don't get any warnings/errors in console. Using latest firefox.
EDIT 1
Comment: The example script you showed just defines function, but it never actually calls them
It actually calls a function which makes an ajax request, please check edited code snippet.
EDIT 2
Comment: Have you tried to put the logic in a callback and then call it in createDiv? May be add some logs to test if its getting called but it unable to find div
I just tried console.log('hello world');
call in one of scripts which are being appended by createDiv()
function, but it does nothing.
EDIT 3
For more details. When page is loaded, I can see
<script type="text/javascript" id="script1" src="http://blabla.com/script1.js"></script>
<script type="text/javascript" id="script2" src="http://blabla.com/script2.js"></script>
<script type="text/javascript" id="script3" src="http://blabla.com/script3.js"></script>
<div id="just_id">Content here</div>
In DOM-Inspector and as mentioned above, there is console.log('hello world');
to test it, but it doesnt get executed.
EDIT 4
Added some CSS through createDiv()
function to document's <head></head>
and it affects my div with id 'just_id'. JS still isn't working.
EDIT 5
Also tried to append inline javascript instead of external one in my function, but still no success. Can see following in DOM-Inspector, but code doesn't log anything.
<script type="text/javascript">
console.log('test');
</script>
EDIT 6
I also tried to import nodes from as suggested here
This method is not allowed to move nodes between different documents. If you want to append node from a different document the document.importNode() method must be used.
and also tried to changed order. 1.css 2.div 3.js like this but still no success... Anyone has an idea what is going on here?
Check the code above
EDIT 7
As suggested in How do you execute a dynamically loaded JavaScript block? I set innerHTML of my div to scripts + content and then appended to DOM like this:
Check the code above
But still without any success.
EDIT 8
Added ajax function code. 3rd paramter in xmlhttp.open("GET","http://blabla.com/api/");
true (asynchronous) and false (synchronous) already tried. Still no success.
EDIT 9
function createDiv()
as suggested in answer:
var dom = parseResponse(responsetext);
var _jr = dom.getElementById('script1'); //<script> tag with src attribute
var _vc = dom.getElementById('script2'); //inline <script> for test purposes only, it should actualy be external script also
var _rv = dom.getElementById('script3'); //inline <script>
var _rw = dom.getElementById('external_div');
var _b = document.getElementsByTagName('body')[0];
var _d = document.createElement('div'); _d.id = 'internal_div';
_d.appendChild(document.importNode(_rw, true));
_d.appendChild(document.importNode(_jr, true));
_d.appendChild(document.importNode(_rv, true)); //without second parameter TRUE, I dont get script content
_d.appendChild(document.importNode(_vc, true)); //without second parameter TRUE, I dont get script content
_b.appendChild(_d);
Doesn't work. Work's only if I take innerHTML of inline scripts from other document, create elements like suggested in answer, set their innerHTML and then append do current document. External script's wont load at all.
EDIT 10
.htaccess from localhost... :
<Files *.html>
Order Deny,Allow
Deny from all
Allow from 127.0.0.1
</Files>
<Files *.php>
Order Deny,Allow
Deny from all
Allow from 127.0.0.1
</Files>
<Files index.php>
Order Allow,Deny
Allow from all
</Files>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /page1/
#RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
</IfModule>
.htaccess from 192.*** ... :
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /direktexpress/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /page2/index.php [L]
</IfModule>
# END WordPress
EDIT 11
So I am probably going to give bounty @Drakes, just for the effort and his spent time on my question and going to show some screenshots what is going on. It is definitely firefox bug, I just tested on chrome and it works.
1st picture: source code of 192.168.2.197/testing/whatever/etc. .htaccess remains the same as in example above
2nd picture is source code for script.js, which is being loaded on 192.168.2.197/testing/whatever/etc. .htaccess remains the same as in example above:
3rd picture is a screenshot of inspector, how does my dom look like:
4th picture.... nothing happens. Just a warning which has nothing to do with my problem (I hope so), because even when I remove all scripts, it still appears.
Is it a firefox bug?
Dynamic loadingThose files can be loaded asynchronously in JavaScript. To load a JavaScript file dynamically: Create a script element. Set the src , async , and type attributes.
To include an external JavaScript file, we can use the script tag with the attribute src . You've already used the src attribute when using images. The value for the src attribute should be the path to your JavaScript file. This script tag should be included between the <head> tags in your HTML document.
Many JavaScript-enhanced web pages have scripts that must be executed automatically when the page is loaded. A web page containing a "scrolling status bar message," for example, should be able to start scrolling the message immediately after the page has loaded, without user interaction.
External Javascript should not contain tag. Show activity on this post. No, <script> tags are not needed otherwise error occurs. For example, external.
The problem is that the code above is mixing appendChild
with innerHTML
. It's not intuitively obvious that the two perform differently in some cases. The former allows newly inserted script nodes to be executed as they are attached to the DOM. The latter doesn't. This has been a head-scratcher for many people. Kindly Google "script and innerHTML" and you will find that you are not alone facing this similar problem.
If you (1) change
_d.innerHTML = _jr + _vc + _rv
to
_d.appendChild(document.importNode(_jr));
_d.appendChild(document.importNode(_vc));
_d.appendChild(document.importNode(_rv));
and additionally (2) change
var _jr = dom.getElementById('script1').outerHTML;
var _vc = dom.getElementById('script2').outerHTML;
var _rv = dom.getElementById('script3').outerHTML;
to
var _jr = dom.getElementById('script1');
var _vc = dom.getElementById('script2');
var _rv = dom.getElementById('script3');
then your scripts will get executed. Here is a demonstration:
var b = document.getElementsByTagName('body')[0];
/* Works */
var s1 = document.createElement('script');
s1.innerHTML = "console.log('I will execute')";
b.appendChild(s1);
/* Fails */
var s2 = document.createElement('script');
s2.innerHTML = "while(1){alert('Do not worry! I will not execute');}";
b.innerHTML = s2.outerHTML;
console.log("It didn't execute");
Tested
I ran the OP's code on my server to replicate the problem as best I can. Given the supplied code I can make it work as intended on my server. I only changed the AJAX URL from http://blabla.com/api/
to api.html
and supplied my own file as none was provided by the OP, but I pieced together what it should contain from the OP's JavaScript). Here are sample results:
index.html
<html lang="en">
<body>
<script>
(function() {
var e = document.createElement('script'); e.type = 'text/javascript'; e.async = true; e.src = 'script.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(e, s);
})();
</script>
</body>
</html>
script.js
This is the OP's code modified to my specifications above (using appendChild
instead of innerHTML
, and the AJAX call returns the contents of api.html below)
function ajaxCall() {
//... some script to send ajax request which calls createDiv() after success
if (window.XMLHttpRequest){
xmlhttp=new XMLHttpRequest();
}
else{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function(){
if(xmlhttp.readyState==4&&xmlhttp.status==200){
createDiv(xmlhttp.responseText);
}
};
xmlhttp.open("GET","api.html");
xmlhttp.send();
}
function parseResponse(response) {
var parser = new DOMParser();
var dom = parser.parseFromString(response, "text/html");
return dom;
}
function createDiv(responsetext)
{
var dom = parseResponse(responsetext);
var _ws = dom.getElementById('styles');
var h = document.getElementsByTagName('head')[0];
h.appendChild(document.importNode(_ws, true));
var _jr = dom.getElementById('script1');
var _vc = dom.getElementById('script2');
var _rv = dom.getElementById('script3');
var _rw = dom.getElementById('my_div');
var _b = document.getElementsByTagName('body')[0];
var _d = document.createElement('div'); _d.id = 'just_id';
_d.appendChild(document.importNode(_jr, true));
_d.appendChild(document.importNode(_vc, true));
_d.appendChild(document.importNode(_rv, true));
_d.appendChild(document.importNode(_rw, true));
_b.appendChild(_d);
}
ajaxCall();
api.html (returned by the AJAX call)
<!DOCTYPE html>
<html>
<body>
<style type="text/css" id="styles"></style>
<script type="text/javascript" id="script1" src="script1.js"></script>
<script type="text/javascript" id="script2">console.log("incline script 2")</script>
<script type="text/javascript" id="script3">console.log("incline script 3")</script>
<div id="my_div"></div>
</body>
</html>
script1.js
console.log("src script1");
Here are the DevTools results to show this is working.
The JavaScript of the page has already been parsed, you need to eval
the result to put it into the window context.
function evalRequest(url) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
eval(xmlhttp.responseText);
}
}
xmlhttp.open("GET", url, true);
xmlhttp.send(null);
};
UPDATE : you might need to get the script as text and then eval it )
function getScriptsAsText() {
var div = document.createElement('div');
var scripts = [];
var scriptNodes = document.getElementsByTagName('script');
for (var i = 0, iLen = scriptNodes.length; i < iLen; i++) {
div.appendChild(scriptNodes[i].cloneNode(true));
scripts.push(div.innerHTML);
div.removeChild(div.firstChild);
}
return scripts;
};
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