As soon as body DOM node is available, I'd like to add a class to it with JavaScript.
I want this to happen as soon as possible, before any of body's children are loaded.
Right now, I'm using an inline script right after opening body tag. Is there a less obtrusive way?
Might be a bit late to the party but...
You can just tap into the browser rendering cycle. Thus you don't have to deal with timeouts which leak memory (if improperly used).
var script = document.createElement('script');
script.src = '//localhost:4000/app.js';
(function appendScript() {
if (document.body) return document.body.appendChild(script);
window.requestAnimationFrame(appendScript);
})();
I would imagine this will differ between browsers.
One solution may be to test for it by placing a script immediately inside the opening <body> tag, then running your code at an interval to add the class.
<body>
<script>
function add_class() {
if(document.body)
document.body.className = 'some_class';
else
setTimeout(add_class, 10); // keep trying until body is available
}
add_class();
</script>
<!-- rest of your elements-->
</body>
jQuery does something similar internally to deal with a particular IE bug.
There isn't a guarantee that the descendant elements won't be loaded though, since again it will depend on when the particular implementation makes the body available.
Here's the source where jQuery takes a similar approach, testing for the existence of the body in its main jQuery.ready handler, and repeatedly invoking jQuery.ready via setTimeout if the body isn't available.
And here's an example to see if your browser can see the <body> element in a script at the top of the element, before the other elements. (Open your console)
Here's the same example without needing the console.
Related
What's, or where is, the safet way to initialize a variable that points to a DOM element, let's say, a div or image?
let myImg;
window.onload (e) => {
myImg = document.getElementById("my_img_1");
}
function doSomething(a, b, c) {
//using myImg
}
Are there any issues with this code? Is this a proper way to initialize a DOM variable?
The load event (what you're currently using) usually isn't a great choice because it happens really late, waiting until all resources (including images, etc.) are loaded. Sometimes you want that, but not often.
You have lots of options. Here's a list in my personal order of preference:
Use type="module" on your script tag so your JavaScript code is a module, not a global script. Modules (both inline and via src) are automatically deferred (see the next item). (They also have other benefits: the code in them isn't at global scope, so they're nicely contained; they're automatically in strict mode; they can load other modules via import.) This works in all modern browsers (so, not with IE11).
Use the defer attribute on your script tag. That tells the browser to download and parse the code, but not to run it until it's done parsing the HTML. Only works with src, though, not inline. This works in all modern browsers and also IE10+.
Put the script at the end of the document, just prior to the closing </body> tag. It won't be run until all the HTML above it has been parsed and put in the DOM. This has always worked.
Use the DOMContentLoaded event. This works in anything even vaguely modern, including IE9+.
Use the load event (what you're currently using; just including it on the list for completeness). This has worked basically forever.
So for example:
<script type="module" src="your-code.js"></script>
your-code.js:
const myImg = document.getElementById("my_img_1");
function doSomething(a, b, c) {
//using myImg
}
Inline example just to demonstrate the deferring:
<script type="module">
const myImg = document.getElementById("my_img_1");
function doSomething(a, b, c) {
myImg.style.border = "2px solid yellow";
}
doSomething();
</script>
<img id="my_img_1" src="data:image/png;base64,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">
Note that the script is above the img, but it still works — because the script execution is deferred.
I have a question about javascript/html.
First, I have this:
var post = document.body.getElementsByClassName("post");
var x=post[i].getElementsByClassName("MyDiv")[0].innerHTML;
I get from the debugger that x is not defined, it doesn't exists.
This javascript function runs onload of the body. I am sure that I gave the right classnames in my javascript, so it should find my div.
So, I read somewhere that sometimes javascript does not find an element because it is not yet there, it is not yet created in the browser ( whatever that means).
Is it possible that my function can't find the div with that classname because of this reason?
Is there a solution?
So, I read somewhere that sometimes javascript does not find an element because it is not yet there, it is not yet created in the browser ( whatever that means).
Browsers create the DOM progressively as they get the markup. When a script element is encountered, all processing of the markup stops (except where defer and async have an effect) while the script is run. If the script attempts to access an element that hasn't been created yet (probably because its markup hasn't been processed yet) then it won't be found.
This javascript function runs onload of the body.
If that means you are using something like:
<body onload="someFn()"...>
or perhaps
<script>
window.onload = function() {
someFn();
...
}
</script>
then when the function is called, all DOM nodes are available. Some, like images, may not be fully loaded, but their elements have been created.
If it means you have the script in the body and aren't using the load event, you should move the script to the bottom of the page (e.g. just before the closing body tag) and see if that fixes the issue.
Okay, instead of calling functions with
body onload, use jQuery's ready() function, or, if you don't want to use jQuery, you can use pure javascript, but this is up to you:
// jQuery
$(document).ready(function() {
var post = document.getElementsByClassName("post"),
x = post[i].getElementsByClassName("MyDiv")[0].innerHTML;
});
// JavaScript
window.onload = function initialization() {
var post = document.getElementsByClassName("post"),
x = post[i].getElementsByClassName("MyDiv")[0].innerHTML;
}
A few side notes, I don't know what the use of innerHTML
is, and also if you're doing a for loop with i then definitely
post that code, that's kind of important.
After some discussion, my answer seems to have worked for you, but you can also place your script at the end of your body tag as #RobG has suggested.
Here is the circumstance:
I have 2 pages:
1 x html page
1 x external Javascript
Now in the html page, there will be internal Javascript coding to allow the placement of the window.onload, and other page specific methods/functions.
But, in the external Javascript I want certain things to be done before the window.onload event is triggered. This is to allow customized components to be initialized first.
Is there a way to ensure initialization to occur in the external Javascript before the window.onload event is triggered?
The reason I have asked this, is to attempt to make reusable code (build once - use all over), to which the external script must check that it is in 'order/check' before the Javascript in the main html/jsp/asp/PHP page takes over. And also I am not looking for a solution in jQuery #_#
Here are some of the links on Stack Overflow I have browsed through for a solution:
Javascript - How to detect if document has loaded (IE 7/Firefox 3)
How to check if page has FULLY loaded(scripts and all)?
Execute Javascript When Page Has Fully Loaded
Can someone help or direct me to a solution, your help will be muchness of greatness appreciated.
[updated response - 19 November 2012]
Hi all, thanks for you advice and suggested solutions, they have all been useful in the search and testing for a viable solution.
Though I feel that I am not 100% satisfied with my own results, I know your advice and help has moved me closer to a solution, and may indeed aid others in a similar situation.
Here is what I have come up with:
test_page.html
<html>
<head>
<title></title>
<script type="text/javascript" src="loader.js"></script>
<script type="text/javascript" src="test_script_1.js"></script>
<script type="text/javascript" src="test_script_2.js"></script>
<script type="text/javascript">
window.onload = function() {
document.getElementById("div_1").innerHTML = "window.onload complete!";
}
</script>
<style type="text/css">
div {
border:thin solid #000000;
width:500px;
}
</head>
<body>
<div id="div_1"></div>
<br/><br/>
<div id="div_2"></div>
<br/><br/>
<div id="div_3"></div>
</body>
</html>
loader.js
var Loader = {
methods_arr : [],
init_Loader : new function() {
document.onreadystatechange = function(e) {
if (document.readyState == "complete") {
for (var i = 0; i < Loader.methods_arr.length; i++) {
Loader.method_arr[i]();
}
}
}
},
load : function(method) {
Loader.methods_arr.push(method);
}
}
test_script_1.js
Loader.load(function(){initTestScript1();});
function initTestScript1() {
document.getElementById("div_1").innerHTML = "Test Script 1 Initialized!";
}
test_script_2.js
Loader.load(function(){initTestScript2();});
function initTestScript2() {
document.getElementById("div_2").innerHTML = "Test Script 2 Initialized!";
}
This will ensure that scripts are invoked before invocation of the window.onload event handler, but also ensuring that the document is rendered first.
What do you think of this possible solution?
Thanking you all again for the aid and help :D
Basically, you're looking for this:
document.onreadystatechange = function(e)
{
if (document.readyState === 'complete')
{
//dom is ready, window.onload fires later
}
};
window.onload = function(e)
{
//document.readyState will be complete, it's one of the requirements for the window.onload event to be fired
//do stuff for when everything is loaded
};
see MDN for more details.
Do keep in mind that the DOM might be loaded here, but that doesn't mean that the external js file has been loaded, so you might not have access to all the functions/objects that are defined in that script. If you want to check for that, you'll have to use window.onload, to ensure that all external resources have been loaded, too.
So, basically, in your external script, you'll be needing 2 event handlers: one for the readystatechange, which does what you need to be done on DOMready, and a window.onload, which will, by definition, be fired after the document is ready. (this checks if the page is fully loaded).
Just so you know, in IE<9 window.onload causes a memory leak (because the DOM and the JScript engine are two separate entities, the window object never gets unloaded fully, and the listener isn't GC'ed). There is a way to fix this, which I've posted here, it's quite verbose, though, but just so you know...
If you want something to be done right away without waiting for any event then you can just do it in the JavaScript - you don't have to do anything for your code to run right away, just don't do anything that would make your code wait. So it's actually easier than waiting for events.
For example if you have this HTML:
<div id=one></div>
<script src="your-script.js"></script>
<div id=two></div>
then whatever code is in your-script.js will be run after the div with id=one but before the div with id=two is parsed. Just don't register event callbacks but do what you need right away in your JavaScript.
javascript runs from top to bottom. this means.. if you include your external javascript before your internal javascript it would simply run before the internal javascript runs.
It is also possible to use the DOMContentLoaded event of the Window interface.
addEventListener("DOMContentLoaded", function() {
// Your code goes here
});
The above code is actually adding the event listener to the window object, though it's not qualified as window.addEventListener because the window object is also the global scope of JavaScript code in webpages.
DOMContentLoaded happens before load, when images and other parts of the webpage aren't still fully loaded. However, all the elements added to the DOM within the initial call stack are guaranteed to be already added to their parents prior to this event.
You can find the official documentation here.
What is the best unobtrusive way of invoking something after the page is being loaded in plain JavaScript? Of course in jQuery I would use:
$(document).ready(function(){...});
but I am not sure about the most reliable approach in plain js.
Clearly
window.onload = ...
is not proper solution, because it would overwrite previous declaration.
What I am trying to do is to insert an iframe into a div after the page is loaded, but maybe there are actually better ways of doing it. My plan is to do something like:
window.onload = function(divId){
var div = document.getElementById(divId);
div.innerHTML = "<iframe src='someUrl' .. >";
}
EDIT:
Apologies for not including all necessary details.
The script is not for my website - the idea is to show a part of my site (a form) on external web sites. The priority is to minimize the effort someone has to put to use my code. That is why I would like to keep everything in js file and absolutely nothing in <script> - except of <script src="http://my.website/code.js" />. If I change URL of an iframe or I would like to add some features, I would like to update the code on all other web sites without asking them to make any changes.
My approach might be wrong - any suggestions are very welcome.
//For modern browsers:
document.addEventListener( "DOMContentLoaded", someFunction, false );
//For IE:
document.attachEvent( "onreadystatechange", someFunction);
`attachEvent` and `addEventListener` allow you to register more than one event listener for a particular target.
See:
https://developer.mozilla.org/en/DOM/element.addEventListener
Also definitly worth looking at how jQuery does it:
http://code.jquery.com/jquery-1.7.js Search for bindReady.
Use window.addEventListener and the events load or DOMContentLoaded:
window.addEventListener('DOMContentLoaded',function(){alert("first handler");});
window.addEventListener('DOMContentLoaded',function(){alert("second handler");});
object.addEventListener('event',callback) will insert an event listener into a queue for that specific object event. See https://developer.mozilla.org/en/DOM/element.addEventListener for further information.
For IE5-8 use window.attachEvent('event',callback), see http://msdn.microsoft.com/en-us/library/ms536343%28VS.85%29.aspx. You can build yourself a little helper function:
function addEventHandler(object,szEvent,cbCallback){
if(typeof(szEvent) !== 'string' || typeof(cbCallback) !== 'function')
return false;
if(!!object.addEventListener){ // for IE9+
return object.addEventListener(szEvent,cbCallback);
}
if(!!object.attachEvent){ // for IE <=8
return object.attachEvent(szEvent,cbCallback);
}
return false;
}
addEventHandler(window,'load',function(){alert("first handler");});
addEventHandler(window,'load',function(){alert("second handler");});
Note that DOMContentLoaded isn't defined in IE lesser 9. If you don't know your recipient's browser use the event load.
Just put your script include at the very end of the document, immediately before or after the ending </body> tag, e.g.:
(content)
(content)
<script src="http://my.website/code.js"></script>
</body>
</html>
All of the markup above the script will be accessible via the usual DOM methods (reference). Obviously, not all ancillary resources (images and such) will be fully loaded yet, but presumably that's why you want to avoid the window load event (it happens so late).
The only real purpose of ready-style events is if you don't control where the script gets included (e.g., libraries) or you need to have something execute prior to the page load and something else after the page load, and you want to avoid having two HTTP requests (e.g., for two different scripts, one before load and one after).
I am new to Java script. I am practicing code.When i put my code in the head section, then i get element null, and when i put it inside body, but before element, then i also get null, but if i put it inside body, but after element then i get the element. I want to ask why i am getting null in case of the first two cases. Here is my code
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="js/attributes.js"></script> // null
</head>
<body>
<script type="text/javascript" src="js/attributes.js"></script> // null
<a id="braingialink"
onclick="return showAttributes();"
href="http://www.braingia.org" >Steve Suehring's Web Site
</a>
<script type="text/javascript" src="js/attributes.js"></script> // ok
</body>
Here is my javascript
var a1 = document.getElementById("braingialink"); //get null in first two cases
window.alert(a1.getAttribute("href"));
a1.setAttribute("href", "www.google.com");
window.alert(a1.getAttribute("href"));
function showAttributes() {
var e = document.getElementById("braingialink");
var elementList = "";
for (var element in e) {
/**
* Sometimes, especially when first programming with JavaScript, you might not know what
* attributes are available for a given element. But you don’t have to worry about that, because
* of a loop that calls the getAttribute() method.
*/
var attrib = e.getAttribute(element);
elementList = elementList + element + ": " + attrib + "\n";
} //end of for()
alert(elementList);
} //end of function showAttributes
And also tell me, placing <script type="text/javascript" src="js/attributes.js"></script>
after the a element, is the same as i write script in the script tag , like
Steve Suehring's Web Site
<script type="text/javascript">
var a1 = document.getElementById("braingialink");
alert(a1.getAttribute("href"));
a1.setAttribute("href","http://www.microsoft.com");
alert(a1.getAttribute("href"));
</script>
Are both things mean to same?
Thanks
The browser parses the document from top to bottom, and if it encounters a <script> block (whether inline script or inclusion of an external JS file) it runs that JavaScript before parsing any more of the document. If that particular code block tries to refer to any elements it can only access the ones above it in the source, i.e., the ones already parsed.
The document.getElementById() method returns null if no element is found for the id you supply, so if you try to use it to access elements below it in the source they've not yet been parsed and can't be found.
The two most common practices to deal with this are:
Put all of your script at the bottom of the <body> such that when it runs all of the elements will have been parsed.
Create an "onload" handler, that is, define a function that will be run as soon as the document finishes loading. You can do this from a script block in the <head> - the JavaScript that defines the onload function is run immediately, but then the function is executed later after everything has loaded.
Following is the simplest way to do option 2:
window.onload = function() {
var x = document.getElementById("x");
// other element manipulation here
};
There is nothing stopping you doing 1 and 2 in the same document, along with throwing some <script> blocks in the middle of the document, but most people find it neater to keep all their code in the one spot.
You're getting null in the head because the DOM has not loaded - your objects are nonexistent at that time. Use this:
window.onload = function () {
// Your code
}
Oh and also take a look at the .ready() function of jQuery here. It would certainly help the headache later on.
Normally you should put script blocks inside the head tag. You can put them in the body tag if you have a special reason, for example to make the script load later because it comes from a slow server.
The reason that you can't access the element, is that the code runs before the browser has parsed the code for the element, so the element simply doesn't exist yet.
You use the load event to run the code after the document is loaded:
window.onload = function() {
// here you put the code that needs to access the elements
}
see http://www.w3schools.com/js/ and http://www.w3schools.com/js/js_whereto.asp
You can place an unlimited number of scripts in your document, and you can have scripts in both the body and the head section at the same time.
It is a common practice to put all functions in the head section, or at the bottom of the page. This way they are all in one place and do not interfere with page content.
You need to understand how web browsers load resources into a page. Firefox -> Firebug add-on Net tab shows the timeline of how resources are loaded. If you are using jQuery or something like it (and you aught to) - then stick your code inside $(document).ready(function() { .. } - that will ensure the page has fully loaded.
Also, it's a good practise to to include your custom js last thing before </body> tag - that way page DOM would have loaded.
Have a read if you want to understand this deeper:
http://www.goodreads.com/book/show/6438581-even-faster-web-sites
and
http://www.goodreads.com/book/show/1681559.High_Performance_Web_Sites
Best would be right before the closing body tag, to not disturb the page loading and rendering at all! It's also recommended by google, for example for analytics snippet and also by facebook!
you get nulls because your script executes while the browser is still loading the page. Since the page might not yet have all elements rendered, you get nulls. you need to run the script when the page has finished loading.
put your script in to the HEAD element, and invoke it on body's onload event.