Function not working if src is a variable? - javascript

With this HTML the function myFunc() can be executed. https://myurl.de/myjs.js has the function myFunc in it.
<head>
<script type="text/javascript" src="https://myurl.de/myjs.js"></script>
<body>
<script type="text/javascript">
myFunc();
</script>
</body>
</head>
But with the second HTML I get an Error: Uncaught ReferenceError: myFunc is not defined.
https://myurl.de/settingsFile.js is a file that includes this url in a var: https://myurl.de/myjs.js so basically SettingsFile.UrlToMyJS is this https://myurl.de/myjs.js
<head>
<script src="https://myurl.de/settingsFile.js"></script>
<script type="text/javascript" id="myid"></script>
</head>
<body>
<script type="text/javascript">
document.getElementById('myid').src = SettingsFile.UrlToMyJS;
myFunc();
</script>
</body>
When I console.log(document.getElementById('myid')) this is the output:
<script type="text/javascript" id="myid" src="https://myurl.de/myjs.js></script> which is correct. It looks exactly like the script in the head of the first html (with the difference that it has the id="myid").
Yet it does not work. Why and how can I fix it?
settingsFile.js:
var defaultURL = 'https://myurl.de/';
var SettingsFile = {
UrlToMyJS : defaultURL + 'myjs.js',
}

The reason it's not working is that you can't add a src to a script element that's already in the DOM — or rather, doing so doesn't do anything. The script element has already been processed.
Instead, create it and then append it:
var script = document.createElement("script");
script.onload = function() {
myFunc();
};
script.src = SettingsFile.UrlToMyJS;
document.head.appendChild(script);
// If you need to support IE8, use the following instead of the previous line:
//document.getElementsByTagName("head")[0].appendChild(script);
That waits for the script to load, then calls myFunc (which should exist by then).
Also note that as I and Jeremy pointed out in the comments, body doesn't go in head, it goes after. It's also generally best to put script tags at the end of body (if you're not using async or defer attributes on them or type="module"). So in all, something like:
<head>
<!-- head stuff here -->
</head>
<body>
<!-- content here -->
<script src="https://myurl.de/settingsFile.js"></script>
<script type="text/javascript">
var script = document.createElement("script");
script.onload = function() {
myFunc();
};
script.src = SettingsFile.UrlToMyJS;
document.head.appendChild(script);
// If you need to support IE8, use the following instead of the previous line:
//document.getElementsByTagName("head")[0].appendChild(script);
</script>
</body>
Another option is to use document.write. This sort of thing may be the last at-least-partially appropriate use of document.write during the main parsing of the page:
<head>
<!-- head stuff here -->
</head>
<body>
<!-- content here -->
<script src="https://myurl.de/settingsFile.js"></script>
<script type="text/javascript">
document.write('<script src="' + SettingsFile.UrlToMyJS + '"><\/script>');
</script>
<script>
myFunc();
</script>
</body>

You can try creating a element and then appending it to your title
For Example (script code) :
var script = document.createElement("script");
script.src = "YOUR_SCRIPT_SRC_HERE";
document.getElementsByTagName('head')[0].appendChild(script);
Here I am creating a new tag in html and then appending it to the head of your html. Even as T.J. Crowder mentioned in the comment try removing your body from the head

Related

Clarification for appendChild

I added a Cookies Consent banner. The requirement is that https://cdn.cookielaw.org/consent/c4337328/OtAutoBlock.js loaded before any other script. I now wonder if appendChild is the right choice. Will it load OtAutoBlock at the exact position I wrote it or will it append the script to the end of the tag (which would be too late). It has to be the first script that's loaded.
<!DOCTYPE html>
<html lang="en">
<head>
<!-- OneTrust Cookies Consent Notice -->
<script type="text/javascript">
if ("%REACT_APP_COOKIE_BAR%" === "true") {
var otAutoBlock = document.createElement("script");
otAutoBlock.setAttribute("type", "text/javascript");
otAutoBlock.setAttribute("src", "https://cdn.cookielaw.org/consent/c4337328/OtAutoBlock.js");
var otSDKStub = document.createElement("script");
otSDKStub.setAttribute("type", "text/javascript");
otSDKStub.setAttribute("src", "https://cdn.cookielaw.org/scripttemplates/otSDKStub.js");
otSDKStub.setAttribute("charset", "UTF-8");
otSDKStub.setAttribute("data-domain-script", "c4337328");
document.getElementsByTagName("head")[0].appendChild(otAutoBlock);
document.getElementsByTagName("head")[0].appendChild(otSDKStub);
function OptanonWrapper() { }
}
</script>
<script type="text/javascript">
/* [Should load after OtAutoBlock loads to avoid tracking before consent was given] */
</script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
document.head.appendChild(script) will add it to the end of the <head> tag, so it will load after all other scripts. You can do two things:
You load it with appendChild at the end, and have all your other scripts with a defer attribute, like this: <script defer> /* something */ </script> The defer forces a script to execute after the page is loaded, but if you load the OtAutoBlock without a defer, it will run before the others. The only thing to note is that defer will cause the scripts not to run last, but after the entire page loads, which includes CSS stylesheets, other JavaScripts, icons, images, HTML content, XHR requests in <script> tags, etc.
<script>
const load = true; // your stuff here
if (load)
{
const script = document.createElement('script');
window.hasRunned = false;
script.text = 'alert(\'OtAutoBlock running.\'); window.hasRunned = true;';
document.head.appendChild(script);
}
</script>
<script defer>
alert('Another script. Has runned OtAutoBlock: ' + window.hasRunned);
</script>
<script defer>
alert('And yet another. Has runned OtAutoBlock: ' + window.hasRunned);
</script>
You use insertBefore to add it before the other scripts, so it will run before them. No need to use defer with this method. This might be what you want if you need the scripts to run before the page loads.
<script>
const load = true; // your stuff here
if (load)
{
let script = document.createElement('script');
window.hasRunned = false;
script.text = 'alert(\'OtAutoBlock running.\'); window.hasRunned = true;';
document.head.insertBefore(script, document.head.children[0]);
}
</script>
<script>
alert('Another script. Has runned OtAutoBlock: ' + window.hasRunned);
</script>
<script>
alert('And yet another. Has runned OtAutoBlock: ' + window.hasRunned);
</script>

Javascript trouble in dynamically call another class in other js file

I'm trying to make a javascript function to call another .js file like this:
scriptCaller.js
function callScript(file){
var script = document.createElement('script');
script.id = file;
script.type = 'text/javascript';
script.async = true;
script.src = "script/"+file+".js";
document.getElementById('scriptSection').appendChild(script);
}
Then I create some class to be called by that script in other file:
divGenerator.js
function divGenerator(){
var self = this;
var div = document.createElement('div');
this.tag = function(){
return div;
}
/*and some other function to style the div*/
}
Then i make the main file to be executed:
main.js
function build(){
callScript('divGenerator');
}
function main(){
var test = new divGenerator();
/*execute some function to style the div*/
document.getElementById('htmlSection').appendChild(script);
}
All the three file will be called in a HTML files that will execute the main function:
myPage.html
<html>
<head>
<title>myPage</title>
</head>
<script src="scriptCaller.js"></script>
<script src="main.js"></script>
<body>
<div id="htmlSection"></div>
<div id="scriptSection"></div>
</body>
</html>
<script>build();</script>
<script>main();</script>
If I correct it should display the styled div, but what I got is an error that said:
TypeError: divGenerator is not a constructor[Learn More]
But, when I move the divGenerator() class to myPage.html it works fine. Any idea to solve this problem?
You need to add scriptCaller.js and divGenerator.js to your html script element.
<html>
<head>
<title>myPage</title>
</head>
<script src="scriptCaller.js"></script>
<script src="main.js"></script>
<script src="scriptCaller.js"></script>
<script src="divGenerator.js"></script>
<body>
<div id="htmlSection"></div>
<div id="scriptSection"></div>
</body>
</html>
<script>build();</script>
<script>main();</script>
You have couple of problems in your code. First of all, do not assign id to script element same as the "exported" global constructor name. You need to remember that anything with id attribute (and name) automatically gets exposed as global variable on window object. It means that divGenerator in your case is going to be reference to HTMLScriptElement, not a constructor function.
Second problem is related to timing, since you are loading script with async attribute. This is good, but you need to realise that in this case you can't expect that script will be loaded when you call main after build(). I would suggest to wrap script creation into promise:
function callScript(file){
return new Promise(function(resolve) {
var script = document.createElement('script');
script.id = 'script-' + file; // Note different id
script.async = true;
script.src = "script/" + file + ".js";
script.onload = resolve
document.getElementById('scriptSection').appendChild(script);
})
}
and use it like this:
<script>
build().then(function() {
main();
})
</script>

Script attribute not set to javascript function value

I am trying to set the attribute of the script tag for a infomous word cloud as follows:
<head>
function getParameterByName(name)
{
...
}
</head>
<body>
<script type="text/javascript"
async data-infomous-id="javascript:getParameterByName('wcid');"
id="embed"
src="http://www.infomous.com/client2/?width=800&height=600&maxWords=40">
</script>
</body>
But the javascript function is never executed. How can I set the data-infomous-id dynamically?
This should do this trick:
jsFiddle
var elem = document.getElementById('embed');
elem.setAttribute('data-infomous-id', getParameterByName('wcid'));

Passing a variable value to a variable in a script function (Javascript)

I would like to know how to pass the value of a variable in JavaScript file to a variable in a script function which is written on top of the HTML file.
I wrote it like this:
myjsfile.js:
var abc = "10";
HTML file:
<html>
<head>
<script type="text/javascript">
(function() {
var test = document.createElement('script'); test.type = 'text/javascript'; test.async = true;
test.src = 'testquery.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(test, s);
alert(abc);
})();
</script>
</head>
<body>
</body>
</html>
I am not getting the output. Please help! Thanks in advance.
Basically I am trying to create a jquery plugin just like Google analytics.
The script has to load first, try using onload
test.onload=function(){alert(abc);}
<html>
<head>
<script type="text/javascript" src="testquery.js"></script>
<script type="text/javascript">
alert(abc);
</script>
</head>
<body></body>
</html>
try this:
(function() {
var test = document.createElement('script');
document.getElementsByTagName('head')[0].appendChild(test);
test.type = 'text/javascript';
test.src = 'testquery.js';
test.onload = function () {
alert(abc);
}
})();​
well.. the onload has already been told but you should at least switch your way of appending it to the head.

how can you determine location of <script> tag from inside said tag?

I am trying to figure out the location of the script tag the current javascript is running in. What is really going on is that I need to determine from inside a src'd, dynamically inserted javascript file where it is located in the DOM. These are dynamically generated tags; code snippet:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>where am i?</title>
<script type="text/javascript" charset="utf-8">
function byId(id) {
return document.getElementById(id);
}
function create_script(el, code) {
var script = document.createElement("script");
script.type = "text/javascript";
script.text = code;
el.appendChild(script);
}
</script>
</head>
<body>
<div id="find_me_please"></div>
<script>
create_script(byId("find_me_please"), "alert('where is this code located?');");
</script>
</body>
</html>
You could give the script an id tag, like this dude does...
You can use document.write to create a dummy DOM object and use parentNode to escape out. For example:
<script>
(function(r) {
document.write('<span id="'+r+'"></span>');
window.setTimeout(function() {
var here_i_am = document.getElementById(r).parentNode;
... continue processing here ...
});
})('id_' + (Math.random()+'').replace('.','_'));
</script>
This assumes you don't actually have control of the <script> tag itself, such as when it's inside a <script src="where_am_i.js"></script> - if you do have control of the <script> tag, simply put an ID on it, as in:
<script id="here_i_am">...</script>
If you are just running this on page load, this works
<script>
var allScripts = document.getElementsByTagName('script');
var thisScript = allScripts[allScripts.length];
alert(thisScript);
</script>

Categories