I often see some JavaScript libraries that are called in the head tag of an html page. However, if these libs call an element in the body tag, there'll be a response (still from the head tag). When I try to call an element from the head, there is no response - why?
Thanks in advance. :)
The browser parses the html page from top to bottom, executing any <script> blocks in place as it finds them. Which means if the JavaScript attempts to access elements on the page it can only see those included higher in the page because the ones lower down have not been parsed yet.
There are two ways to deal with this:
Put your <script> block at the bottom, just before the closing </body> tag (or at least put it after the elements it needs to reference), and/or
Use an onload (or, if you like jQuery, a $(document).ready()) handler.
One way to setup an onload handler is like this:
<head>
<script>
window.onload = function() {
// this function will be called by the browser after
// the entire page has loaded and thus code in the function
// can access any element on the page.
};
</script>
</head>
<body>
... various elements ...
</body>
You may have also seen something like this:
<body onload="someFunction();">
Where someFunction() can be defined in a <script> block in the <head>. It's basically the same thing, but it's so 1990s to do it with an attribute in the html like that. (Actually even the window.onload() is out of date now, but it works and I don't have time to explain the .addEventListener() method.)
That's beacause you propably are trying to call elements before they exist, ie. the HTML isn't parsed yet. To avoid this, you have to wait untill the page is completed, and then execute your script.
To achieve this, you have to assign your function into a onload-event. For example:
<body onload="your_func">
Related
I have a chunk of JavaScript code:
<script src='blah.js' type='text/javascript'></script>
How can this be removed or disabled with JavaScript?
If the script tag is received in a string via AJAX:
str = str.replace("<script src='blah.js' type='text/javascript'></script>", "");
However, if the script tag is in the current document, there is no way to disable it, because:
If it is in the part of the document which has already been parsed (i.e. above the current script), it has already been executed. While you can remove the script element, just like any element, there is no way to rewind time and automatically undo the effects the script has.
If it is in the part of the document which has not yet been parsed (i.e. below the current script), you cannot affect it, as it does not exist yet.
You can grab the script like any other element, you can do this:
document.querySelector("script").remove();
If you have a lot of script tags you can just grab the one you want like accessing a array element like so:
document.querySelectorAll("script")[1].remove();
The code above removes the second script tag in a page.
I wrote the following page as a DOM traversal demo:
<html>
<head>
<title>DOM Traversal</title>
</head>
<body>
<h1>Sample H1</h1>
<div id="text">
<p>Sample paragraph</p>
</div>
</body>
<script>
// Traversing the DOM tree
"use strict";
var node = document.body;
while(node) {
console.log(node);
node = node.lastChild;
}
</script>
</html>
Surprisingly, the output I'm getting is the body tag followed by the script tag. How is this possible? Isn't the script tag a sibling of the body tag? Also, why aren't the child nodes of body being traversed?
You cannot add your script element outside of the head or body elements. The browser is auto-correcting your HTML, moving the script into the end of your body, which explains the result you are getting.
The html element may only contain the head and body elements as its children. Anything else must be placed within these two elements.
On top of what iMoses said, your script block will run before the entire document is parsed, as it doesn't wait on the domReady event. This seems to cause a race condition.
If you leave your script where it is, but wait for domReady, you get a slightly different result (albeit still not what you want).
EDIT: change your script to output "node.outerHTML" instead, and you will see that the script block gets moved or rather duplicated into the body.
Without waiting for document ready, you end up with two script blocks while the script is running - one is your original, the other one at the end of the body as iMoses pointed out.
Waiting for document ready, you will find that only the (moved) one inside the body remains.
A good place to start with resolving this kind of 'issue' is to validate the source first.
Tools such as the W3C HTML validator will help you avoid this kind of problem going forward:
http://validator.w3.org/check
Validating your code returns the following:
Line 11, Column 12: document type does not allow element "SCRIPT" here
<script>
The element named above was found in a context where it is not allowed. This could mean that you have incorrectly nested elements -- such as a "style" element in the "body" section instead of inside "head" -- or two elements that overlap (which is not allowed).
One common cause for this error is the use of XHTML syntax in HTML documents. Due to HTML's rules of implicitly closed elements, this error can create cascading effects. For instance, using XHTML's "self-closing" tags for "meta" and "link" in the "head" section of a HTML document may cause the parser to infer the end of the "head" section and the beginning of the "body" section (where "link" and "meta" are not allowed; hence the reported error).
I'm using a nifty little script called Tabifier (http://www.barelyfitz.com/projects/tabber/)
Now, long story short, this script, which I run in my head tag, creates a <ul> with <li>s containing <a>s. Also in the head tag it creates IDs for these <a>s. When I inspect the loaded site I can clearly see the ID tags present. However, I cannot call them using getElementById. I've been using
<script>
document.getElementById('rightpanelnav1').style.padding='200px';
</script>
as a sample script in different parts of my code but to no avail. I'm wondering wether it's the placement or order in which these things are defined in my code that's causing it not to recognize the ID. What do you think?
EDIT: I recieved a great answer below, but I still can't get 'rightpanelnav1' to register onclick events...? It's an , there shouldn't be a problem, right? And when I click it, the entire page has been loaded for several seconds...
Firstly, in order to access an element in the DOM, the element must be a part of the DOM (document). So if you place your <script> with getElementById in the page at a place prior to where the element is loaded, it will not see the element in the DOM.
Secondly, it is highly probable that this library you use does its modification on page load, which would mean that no matter where you place your <script> it would have no chance of seeing these elements before running.
As a result, you should have your script wait as well, and do this:
window.onload = function(){
document.getElementById('rightpanelnav1').style.padding='200px';
};
Or for a click event
window.onload = function(){
document.getElementById('rightpanelnav1').onclick = function(){
alert("clicked!");
};
};
How do you insert an HTML element dynamically (using prototype) at the current position if you don't know the id of the parent element? All examples I've seen assumes the element has some kind of id.
I.e.
<script>
function addSomeHtmlAtCurrentPosition()
{
current_element = ...; // Magic?
current_element.insert(...);
}
</script>
<div>
<script>
addSomeHtmlAtCurrentPosition();
</script>
<!-- should insert something here... -->
</div>
<div>
<script>
addSomeHtmlAtCurrentPosition();
</script>
<!-- ... and then here -->
</div>
I've tried using prototype with $$('div').last(), but that doesn't seem to work (last() sometimes reports back another div if I use libraries such as livepipe).
What I really want is something similar to document.write, but using prototype instead of raw html.
The only way I can think of is finding the <script> element and insert the element before/after the script. The thing is, all DOM methods need a DOM node to operate on. Executing scripts that modify the DOM before the document has loaded isn't a good and safe idea.
Similar questions linked below.
JavaScript: get the current executing <script> node?
How may I reference the script tag that loaded the currently-executing script?
If I have some javascript/jQuery acting on a particular div inside tags (for an animation), can I just put the javascript (in a src="link-to-my-js.js" file) right next to my div?
I mean something like the following:
<body>
<div id="special">Some html</div>
<script type="text/javascript">javascript related to my div tag above...</script>
</body>
whereever you add your code wrap it with document .ready.
It will wait till all the dom is ready, so you will be safe.
<script type="text/javascript">
$(document).ready(function() {
});
</script>
You can put them anywhere you want, but
For performance reasons, it's best to put them at the bottom of the page.
DOM manipulation before the page has loaded can cause problems, especially with IE, for example this google maps problem.
You can add the tag anywhere you please. Remember though that if your script tries to act on an element that has not yet been loaded it will fail.
So if your load your script tag before your div and the script isn't activated by an onload event or something similar element will not be found.
On the contrary if the tag appears after the element you can manipulate it as normal.
It does not matter where you put it if you wrap your code with the $(function(){/*code here*/})
reference: http://api.jquery.com/jquery/#jQuery3