Say we have the following script reference
<script src="https://pagead2.googlesyndication.com/pagead/osd.js"></script>
How to make javascript execute it several times on page load, like (in pseudo code):
<script>
var i;
for (i = 0; i < 5; i++) {
<script src="https://pagead2.googlesyndication.com/pagead/osd.js"></script>
}
</script>
You can use this piece of code to achieve what you need.
<script>
var elem = document.createElement('script');
elem.type = 'text/javascript';
elem.async = true;
elem.src = 'https://pagead2.googlesyndication.com/pagead/osd.js';
for(var i=0; i<5; i++){
var s = document.getElementsByTagName('script')[i];
s.parentNode.insertBefore(elem, s);
}
</script>
This should load as well as execute the script. #BenM
First of all I didn't understand why are you trying to add reference to same js file repeatedly. Its enough if you load the file only once. If you are trying this to execute some code inside the js file then just write that piece of code inside a function and call that function on window onload. Hope that helps
Related
I'm wondering if there is a way to get a handle on the DOM element that contains the script inside it. So if I had:
<script type="text/javascript> var x = ?; </script>
Is there a way that I can assign "x" a reference to the script element that contains "x"?
There isn't a truly safe way.
The closest you can come is to use getElementsByTagName to get all the scripts, get its length, get the last script element, then work from there.
This can fail if the script is deferred or if the script has been dynamically added to the page before another script element.
You could include some marker text in the script element, and then (similar to what David said), you can loop through all the script elements in the DOM (using getElementsByTagName or whatever features your library, if you're using one, may have). That should find the element reliably. That would look something like this (live example):
<body>
<script id='first' type='text/javascript'>
(function() {
var x = "MARKER:first";
})();
</script>
<script id='second' type='text/javascript'>
(function() {
var x = "MARKER:second";
})();
</script>
<script id='third' type='text/javascript'>
(function() {
var x = "MARKER:third";
})();
</script>
<script id='last' type='text/javascript'>
(function() {
var scripts, index, script;
scripts = document.getElementsByTagName("script");
for (index = 0; index < scripts.length; ++index) {
script = scripts[index];
if (script.innerHTML.indexOf("MARKER:second") >= 0
&& script.id !== "last") {
display("Found MARKER:second in script tag #" + script.id);
}
}
function display(msg) {
var p = document.createElement('p');
p.innerHTML = msg;
document.body.appendChild(p);
}
})();
</script>
</body>
Note that, like the script above, if you're looking for a script tag marker from within a different script tag, you'll need to handle that. Above it's handled by checking the ID of the script tag, but you can also just break it up in the one you don't want to find, like this (live example):
if (script.innerHTML.indexOf("MARKER:" + "second") >= 0) {
display("Found MARKER:" + "second in script tag #" + script.id);
}
I know they do the same thing more or less, its just the approach on how its done.
<script src="example.js" type="text/javascript" charset="UTF-8"></script>
<script type="text/javascript">
function OptanonWrapper() { }
</script>
<script type="text/javascript">
var x = x || [];
(function(){
setTimeout(function(){
var d = document, f = d.getElementsByTagName('script')[0], s = d.createElement('script'); s.type = 'text/javascript';
s.async = true; s.src = "example.js"; f.parentNode.insertBefore(s,f);
}, 1);
})();
</script>
--
I am not a native js programmer so your help would be greatly appreciated.
In the first example, the second <script> tag will only execute after example.js has finished loading.
In the second example, the <script> tag that loads example.js is created dynamically and inserted into the document (in a needlessly roundabout way, if I may add my own two cents), and it will start loading asynchronously, i.e. it does not delay the execution of any <script> tags after it. The same effect could be achieved this way:
<script src="example.js" async></script>
<script>
function OptanonWrapper() { }
</script>
Read up on the <script> element on MDN for more details:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script
One of my clients would like to execute a script after the rest of the page content has fully loaded.
I suggested the following jquery function:
script>
$(window).load(function() {
$.getScript("http://jact.atdmt.com/jaction/JavaScriptTest");
});
</script>
Which calls the script above only after the rest of the page has loaded. However, the script above is also supposed to call another script after it executes. This looks something like the below:
function AT_tags(){
try{var tags = new Array();
var imgs = new Array();
tags = [];
for(var i=0; i<tags.length; i++)
{ imgs[i] = new Image();
imgs[i].src = tags[i];}
this.csk='Test';
}catch(e){this.csk='Error';}}
var AT_csk = new AT_tags();
document.write('<s'+'cript language="JavaScript" src="http://jact.atdmt.com/jaction/KamuiTag/"></scr'+'ipt>');
The second script - that says jaction/KamuiTag - isn't executing when the first script is called this way.
Can someone please explain to me why a script within a script that executes using the above jquery function would not get called?
Also, does anyone have any fixes or suggestions?
Thanks,
Try using the DOM.
document.head = document.head || document.getElementsByTagName('head')[0];
var js = document.createElement('script');
js.setAttribute('type','text/javascript');
js.setAttribute('src','http://jact.atdmt.com/jaction/KamuiTag/');
document.head.appendChild(js);
You can use callback for $.getScript() like below;
<script>
$(window).load(function() {
$.getScript("http://jact.atdmt.com/jaction/JavaScriptTest", function() {
function AT_tags(){
try{var tags = new Array();
var imgs = new Array();
tags = [];
for(var i=0; i<tags.length; i++)
{ imgs[i] = new Image();
imgs[i].src = tags[i];}
this.csk='Test';
}catch(e){this.csk='Error';}}
var AT_csk = new AT_tags();
$.getScript("http://jact.atdmt.com/jaction/KamuiTag/");
});
});
</script>
I'm wondering if there is a way to get a handle on the DOM element that contains the script inside it. So if I had:
<script type="text/javascript> var x = ?; </script>
Is there a way that I can assign "x" a reference to the script element that contains "x"?
There isn't a truly safe way.
The closest you can come is to use getElementsByTagName to get all the scripts, get its length, get the last script element, then work from there.
This can fail if the script is deferred or if the script has been dynamically added to the page before another script element.
You could include some marker text in the script element, and then (similar to what David said), you can loop through all the script elements in the DOM (using getElementsByTagName or whatever features your library, if you're using one, may have). That should find the element reliably. That would look something like this (live example):
<body>
<script id='first' type='text/javascript'>
(function() {
var x = "MARKER:first";
})();
</script>
<script id='second' type='text/javascript'>
(function() {
var x = "MARKER:second";
})();
</script>
<script id='third' type='text/javascript'>
(function() {
var x = "MARKER:third";
})();
</script>
<script id='last' type='text/javascript'>
(function() {
var scripts, index, script;
scripts = document.getElementsByTagName("script");
for (index = 0; index < scripts.length; ++index) {
script = scripts[index];
if (script.innerHTML.indexOf("MARKER:second") >= 0
&& script.id !== "last") {
display("Found MARKER:second in script tag #" + script.id);
}
}
function display(msg) {
var p = document.createElement('p');
p.innerHTML = msg;
document.body.appendChild(p);
}
})();
</script>
</body>
Note that, like the script above, if you're looking for a script tag marker from within a different script tag, you'll need to handle that. Above it's handled by checking the ID of the script tag, but you can also just break it up in the one you don't want to find, like this (live example):
if (script.innerHTML.indexOf("MARKER:" + "second") >= 0) {
display("Found MARKER:" + "second in script tag #" + script.id);
}
I'm working on a web page where I'm making an AJAX call that returns a chunk of HTML like:
<div>
<!-- some html -->
<script type="text/javascript">
/** some javascript */
</script>
</div>
I'm inserting the whole thing into the DOM, but the JavaScript isn't being run. Is there a way to run it?
Some details: I can't control what's in the script block (so I can't change it to a function that could be called), I just need the whole block to be executed. I can't call eval on the response because the JavaScript is within a larger block of HTML. I could do some kind of regex to separate out the JavaScript and then call eval on it, but that's pretty yucky. Anyone know a better way?
Script added by setting the innerHTML property of an element doesn't get executed. Try creating a new div, setting its innerHTML, then adding this new div to the DOM. For example:
<html>
<head>
<script type='text/javascript'>
function addScript()
{
var str = "<script>alert('i am here');<\/script>";
var newdiv = document.createElement('div');
newdiv.innerHTML = str;
document.getElementById('target').appendChild(newdiv);
}
</script>
</head>
<body>
<input type="button" value="add script" onclick="addScript()"/>
<div>hello world</div>
<div id="target"></div>
</body>
</html>
You don't have to use regex if you are using the response to fill a div or something. You can use getElementsByTagName.
div.innerHTML = response;
var scripts = div.getElementsByTagName('script');
for (var ix = 0; ix < scripts.length; ix++) {
eval(scripts[ix].text);
}
While the accepted answer from #Ed. does not work on current versions of Firefox, Google Chrome or Safari browsers I managed to adept his example in order to invoke dynamically added scripts.
The necessary changes are only in the way scripts are added to DOM. Instead of adding it as innerHTML the trick was to create a new script element and add the actual script content as innerHTML to the created element and then append the script element to the actual target.
<html>
<head>
<script type='text/javascript'>
function addScript()
{
var newdiv = document.createElement('div');
var p = document.createElement('p');
p.innerHTML = "Dynamically added text";
newdiv.appendChild(p);
var script = document.createElement('script');
script.innerHTML = "alert('i am here');";
newdiv.appendChild(script);
document.getElementById('target').appendChild(newdiv);
}
</script>
</head>
<body>
<input type="button" value="add script" onclick="addScript()"/>
<div>hello world</div>
<div id="target"></div>
</body>
</html>
This works for me on Firefox 42, Google Chrome 48 and Safari 9.0.3
An alternative is to not just dump the return from the Ajax call into the DOM using InnerHTML.
You can insert each node dynamically, and then the script will run.
Otherwise, the browser just assumes you are inserting a text node, and ignores the scripts.
Using Eval is rather evil, because it requires another instance of the Javascript VM to be fired up and JIT the passed string.
The best method would probably be to identify and eval the contents of the script block directly via the DOM.
I would be careful though.. if you are implementing this to overcome a limitation of some off site call you are opening up a security hole.
Whatever you implement could be exploited for XSS.
You can use one of the popular Ajax libraries that do this for you natively. I like Prototype. You can just add evalScripts:true as part of your Ajax call and it happens automagically.
For those who like to live dangerously:
// This is the HTML with script element(s) we want to inject
var newHtml = '<b>After!</b>\r\n<' +
'script>\r\nchangeColorEverySecond();\r\n</' +
'script>';
// Here, we separate the script tags from the non-script HTML
var parts = separateScriptElementsFromHtml(newHtml);
function separateScriptElementsFromHtml(fullHtmlString) {
var inner = [], outer = [], m;
while (m = /<script>([^<]*)<\/script>/gi.exec(fullHtmlString)) {
outer.push(fullHtmlString.substr(0, m.index));
inner.push(m[1]);
fullHtmlString = fullHtmlString.substr(m.index + m[0].length);
}
outer.push(fullHtmlString);
return {
html: outer.join('\r\n'),
js: inner.join('\r\n')
};
}
// In 2 seconds, inject the new HTML, and run the JS
setTimeout(function(){
document.getElementsByTagName('P')[0].innerHTML = parts.html;
eval(parts.js);
}, 2000);
// This is the function inside the script tag
function changeColorEverySecond() {
document.getElementsByTagName('p')[0].style.color = getRandomColor();
setTimeout(changeColorEverySecond, 1000);
}
// Here is a fun fun function copied from:
// https://stackoverflow.com/a/1484514/2413712
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
<p>Before</p>