Inserting a script dynamically in the DOM - javascript

I'm trying to understand why this code doesn't work and the alert output is just blank.
<script type="text/javascript">
(function() {
...
var s = document.getElementsByTagName('script')[0]; alert(s.innerHTML);
s.parentNode.insertBefore(res, s);
...
})();
</script>
It should add res before s if I'm not wrong. That's what I specifically need, as I tried to append it to body and it's added successfully (after doing that though I have to run some code inside this function, so if the script is not loaded before it, such code will error).
This function should run when document is loaded or is that the problem? In particular, the getElementsByTagName function seems to not return anything.
Thanks to everyone.

You cannot run this type of code before the document is loaded. This code has to be loaded before it can be run (see the circular argument here). And, by then, much of the rest of the document has been loaded. You can dynamically load scripts AFTER the document has been loaded. If you need a script loaded before other scripts, then you either have to put them all in the document statically in the order you need them to be run or you need to add them all dynamically in the order you need them to run and you will need to keep track of completion of one load before loading the next.
If you care to describe the broader problem you're trying to solve, we can probably suggest a more elegant solution than what you are pursuing.

Related

How can I wait until a newly created Element is "ready" (all scripts downloaded)

I'm working on a piece of code that glues Sammy JS (router) and Knockout JS together.
So, this is my problem,
<script id="MyTemplate" type="text/html">
// [HTML Containing a script link (Encoded HTML)]
</script>`
I use jQuery to create an instance of this template :
var TInstance = $($("#MyTemplate").text())
Then, I want to inject the new html TInstance into my <body> or an other existing tag
$("body").html(TInstance)
All Good, now I want to do ko.applyBindings to bind the new TInstance to an ViewModel and it works.
The problem I have is: when I have an <script src="..." /> inside TInstance,
I want to wait until that script is downloaded and parsed, then do ko.applyBindings.
So I tried $(TInstance).ready(() => {ko.applyBindings(...)}), It works the first time the page loaded, but if I redo the whole process, swapping in a new TInstance the ready handler on the new TInstance won't fire.
What should I do?
Ok, this answer will not be "copy & paste and play", it will require some tweaking from you, but i think you will get the concept and you will manage.
Without adding a dependency management module, and without restructuring you code ( usually plain script tags don't get injected dynamically along with html for the same reason you have troubles right now. Its a good idea to load script tags with html for the first page load, but any content added later on, especially if some flow is required, will need programmatic handling, hence the need for module management frameworks for larger projects)
One way to do it is to stop your code execution flow and poll the enviroment to see if your script is loaded. i.e:
var demoInterval = setInterval(function(){
if(myCondition){
clearInterval(demoInterval );
functionThatStartsTheRestOfTheLogicFlow(); // this could apply bindings etc etc
}
},50);
Now for example, if you where loading jQuery with the script tag your condition could be
typeof($) !== 'undefined'
It would poll every 50 milliseconds until $ is defined, and then it would call a function to clear the polling and continue your logic flow.
In your case the condition could be the definition of a function/model, a flag-like variable that your custom js file can set and the polling would expect to read at some point etc etc.
Even better would be to remove the script tag from the html and load the script dynamically by javascript so that you can utilize the onload event of the specific script that is required, you can read an example here. Programatically controlling these cases is much easier for the developer.
Hope this helps
have resolved the problem by using a 0ms setTimeout call
setTimeout(() => { /*all new resources have been loaded and the html rendered*/ });
Help: https://eager.io/blog/how-to-decide-when-your-code-should-run/

Stop all scripts in a page from loading

I've been trying to get this code working in Google Chrome but I can't seem to be able to stop server requests from "removed" scripts from happening.
What I'm trying to do is remove all scripts in a page, the code below removes the scripts from the DOM but they still load and execute.
Code:
document.addEventListener("DOMContentLoaded", function(){
var e2 = document.getElementsByTagName("script");
for(var i = e2.length; i--; e2[i].parentNode.removeChild(e2[i]));
});​
Any ideas?
Scripts are blocking, so any script tag that appears before the closing body tag is downloaded, parsed and executed before the DOMContentLoaded event.
You could always take a look at async or defer attributes on your script tags, but you'd still be guessing if they have been executed or not by the time your DOMContentLoaded listeners gets executed.
You should really try to look for an alternative method to achieve what you want to accomplish here. Might I ask what you're trying to do?

loading a js file asynchronously from a js file that loads asynchronously

I had a javascript file(initial.js) on the page inserted through the script tag like so:
<script src="initial.js"></script>
This file creates dom elements(let say two links) and also loads another jQuery plugin(plugin.js) asynchronously via jQuery ajax method. Clicking on those two links brings up a module from the jQuery plugin(plugin.js).
The javascript file(initial.js) was then modified to load asynchronously on the page via jQuery ajax instead of via script tag. This has resulted in some events not getting attached to the links intermittently and this results in the plugin not being called.
I believe the browser is loading the async scripts in its own order and hence the links fail to launch the plugin intermittently. Any pointers to resolve this issue with this new set up?
At a high-level, I think you need to look into something like require.js. Alternatively, you could look into some jQuery event handling code which allows you to listen on load events of calls which may help you determine when one script loaded before loading the next one.
You have probably tried something like this in the past:
var output;
$.get('data.php',function(data){
output=data;
});
alert(output);
You will get an undefined error because Javascript doesn't wait around for the AJAX call to be returned before moving onto the next code.
Same thing goes for scripts. If you place multiple calls to multiple scripts, you will probably get the smallest one returned the quickest, and that script executed. If you load a script that is 10kb and then one that is 1kb, the 1kb script will probably return the quickest and then be executed even though it was called after the 10kb script.
To correct this, you could make a queue system and then only load each script after the previous has loaded:
var scripts=['script1.js','script2.js','script3.js'];
$(document).ready(function(){
loadScript();
});
function loadScript(){
if(sendQueue.length==0)
return;
$.getScript(scripts[0],function(){
scripts=scripts.slice(1);
loadScript();
});
}
But if you are loading scripts from within scripts from within scripts... very Inception like, then this still may not work.

Head js Problems with loading javascript files

I'm using Head js to load my javascript files in parallel. I added head js to my head and then used head.js("path/to/file/my.js"); but when I load my webpage the script is missing. Only after refreshing a few times does the whole script work properly. Why do I need to refresh it to make it work? Any suggestions would be appreciated!
As the scripts are loaded asynchronously, you can't use it immediately. After you have refreshed the page, it will find the script in the cache, so it will load in time for any code needing it sometimes.
Use the ready method for any code that needs the script:
head.ready(function() {
// any code that needs the script to be loaded first
});
Another way is to mark your library and then get the ready event when your script is loaded. Read more from http://headjs.com/ Labeling scripts.
head.ready("your", function() {
});
head.js(
{jquery: "http://http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"},
{tools: "http://cnd.jquerytools.org/1.2.5/tiny/jquery.tools.min"},
{your: "http://a.heavy.library/we/dont/want/to/wait/for.js"},
// label is optional
"http://can.be.mixed/with/unlabeled/files.js"
);

Run JavaScript function when the DOM is "ready"?

I'm using a JavaScript upload script that says to run the initialize function as soon as the DOM is ready. I currently have it working just fine with either a call to the function with body.onload or directly after the function is defined. The function builds some HTML in a placeholder div that acts as the file uploader tool.
My question is what is the best practice here? Since it works for now, why would the instructions say to run the init function as soon as the DOM is ready? Should I be adding a <script> tag directly after the placeholder DIV for example?
<script>
window.addEventListener("DOMContentLoaded", function() {
// do stuff
}, false);
</script>
You do that so you know all the parsed elements are available in the DOM etc.
The easiest solution is using jQuery and its $(document).ready(function() { .... }); function. Instead of .... you put your own code.
Note that it basically does the same thing #Shadow2531 suggested, but also works in old browsers not supporting that event.
The DOM is usually ready before onLoad runs. onLoad only runs after everything loads - external scripts, images, stylesheets, etc.
But the DOM, i.e. the HTML structure is ready before that. If you run the code at the bottom of the page (or after the parts of the page the script works with) that will work fine as well.
In 2015 you have two options with modern browsers:
document.onload
this fires when the document is loaded, but other resources (most notably images) have not necessarily finished loading.
window.onload
this fires when the document is loaded, AND all other resources (again, most notably images) are loaded.
Both of the above events would be better utilized with window.addEventListener() of course, as multiple listeners would be allowed.
You could also just move the <script> to the bottom of your page like this:
<html>
<body>
<main></main>
<script>
// code
</script>
</body>
</html>
As you probably know you should not run init functions before the DOM is fully loaded.
The reason you must run the init function as soon as the DOM is ready, is that once the page has loaded the user starts hitting buttons etc. You have to minimize the small inavoidable gap where the page is loaded and the init-functions haven't run yet. If this gap gets too big (ie. too long time) your user might experience inappropiate behaviour... (ie. your upload will not work).
Other users have provided fine examples of how to call the init function, so I will not repeat it here... ;)
Get jQuery and use the following code.
$(document).ready(function(){
// Do stuff
});
var Tette =
{
init: function()
{
/* Your HTML code */
}
};
Core.start(Tette);
You can try in this code, registering "Core.start(your object)" on the last line of the script. This is a way to load in safety your functions after the DOM loading.

Categories

Resources