Javascript: Do properties of `document` include nodes beyond `body`? - javascript

I'm reading through Mozilla's Introduction to DOM, and found one of their examples interesting - where body appeared as a property of document. This was atypical to me because I had only seen examples of nodes being accessed using get.
I tried three different ways of accessing the body element of document,
document.body.appendChild(_someNode_)
document['body'].appendChild(_someNode_)
document.getElementsByTagName('body')[0].appendChild(_someNode_)
and found the example shown in Mozilla to be a nice shorthand (first line).
At this point, I felt that I could simply chain nodes with this shorthand, but found that it was undefined for anything but body.
Here's an example:
console.log(document.body); // #document
console.log(document.body.p); // undefined
console.log(document.body.getElementsByTagName('p')[0]); // <p></p>
What's going on here?

There are some tags that get their own properties in document, but they are rare, and in some cases are browser-dependent. An example would be document.forms that contains the collection of all form tags, and document.frames, that contains a collection of al frames and iframes contained by a page.
But you should avoid these properties, and use instead .getElementById(), .getElementsByTagName(), and the more recent and versatile .querySelector() and .querySelectorAll()

The Document object is special. It has a property called body that returns the <body> element, but in general you have to use getElementsByTagName() and its friends.

Related

What is the relationship between Document and Element? Why does a parent element also have getElementsByTagName method?

I've been really troubled in the relationship between Document and Element since I found that a ul element also can use getElementsByTagName method to get its descendants.
I can understand that the document object, as an instance of Document, has those methods that is inherited from Document. But I can't understand why an instance of Element also have those methods.
Where are those methods from? What is the relationship between Document and Element?
Strictly speaking, Document.getElementsByTagName and Element.getElementsByTagName are different methods. But it makes sense for both Document and Element to have such a method: A document has "child" elements, and an element does, too.
To answer your broader question, Document and Element both inherit from Node (as do DocumentFragment and a few other interfaces). Node defines a number of properties and methods common to Document and Element, such as nodeType, childNodes, and appendChild(). As MDN notes, "These interfaces may return null in particular cases where the methods and properties are not relevant," so e.g. document.parentNode returns null. But as it turns out, your example getElementsByTagName isn't defined by Nodeā€”it's defined separately by Document and Element.
For understanding the DOM, MDN (where all of the above links lead) is your best friend. It'll tell you not only what each property and method is for, but also what interface it's defined in.

does getElementsByTagName() return exact match only?

I'm thinking it should return only exact match.
I see something like in source I have to work with:
var someArray = someObject.getElementsByTagName("item");
Except when I inspect the DOM, I don't see any tags named "items".
There are some css classes '.some_item_details'.
Subsequently I see an error about the element being null, which makes sense to me. What bugs me is that I'm seeing this in production codebase. So I'm thinking, "surely no one would commit something like this, I must be missing something".
Wouldn't 'item' have to exist a custom tag?!?
check getElementsByTagName()
Indeed,getElementsByTagName matches makes exact matches.
Returns an HTMLCollection of elements with the given tag name. The
complete document is searched, including the root node. The returned
HTMLCollection is live, meaning that it updates itself automatically
to stay in sync with the DOM tree without having to call
document.getElementsByTagName() again.
Note:
document.getElementsByTagName() is similar to
element.getElementsByTagName(), except that its search encompasses the
whole document.
#NiettheDarkAbsol's comment :
var someArray = someObject.getElementsByTagName("item");
Indeed, the code snippet you have shown would be searching for item
tags. This might be okay if someObject is an XML context.

Why does JavaScript's getElementsByClassName provide an object that is NOT an array?

I'm trying to get a list in JavaScript (not using jQuery) of all the elements on the page with a specific class name. I therefore employ the getElementsByClassName() function as follows:
var expand_buttons = document.getElementsByClassName('expand');
console.log(expand_buttons, expand_buttons.length, expand_buttons[0]);
Note that I have three anchor elements on my page with the class 'expand'. This console.log() outputs
[] 0 undefined
Next, for kicks, I threw expand_buttons into its own array as follows:
var newArray = new Array(expand_buttons);
console.log(newArray, newArray.length);
This suddenly outputs
[NodeList[3]] 1
and I can click through the nodelist and see the attributes of the three 'expand' anchor elements on the page. It's also worth noting that I was able to get my code working in a w3schools test page.
It may also be of note that my use of document.getElementsByName actually does output (to the console) an array of elements, but when I ask for its length, it tells me 0. Similarly, if I try to access an array element using array_name[0] as normal, it outputs 'undefined', despite there clearly being an element inside of an array when I print the object to the console.
Does anybody have any idea why this might be? I just want to loop through DOM elements, and I'm avoiding jQuery at the moment because I'm trying to practice coding with vanilla JavaScript.
Thanks,
ParagonRG
It's not so much a JavaScript thing as it is a web browser thing. That API is supplied by a native object (the document object), and by the DOM spec it returns a NodeList object. You can treat a NodeList like an array, and it's similar, but distinctly different (as you've noticed).
You can always copy a NodeList to a new array:
var nodeArr = Array.prototype.slice.call(theNodeList, 0);
or in modern ES2015 environments:
var nodeArr = Array.from(theNodeList);
JavaScript always exists in some runtime context, and the context can include all sorts of APIs that provide facilities to JavaScript code. A web browser is one of those contexts. The DOM is specified in a way that's not especially partial to JavaScript; it's a language-neutral interface definition.
I guess the short version of this answer would be, "because it just does."
It doesn't return an array because the object it returns is "live", specifically it is a live NodeList:
In most cases, the NodeList is a live collection. This means that changes on the DOM tree are going to be reflected on the collection.

document is an alias name?

Is document an alias of Sys.UI.DomElement in JavaScript?
I have come across this example in msdn.
$addHandler(Sys.UI.DomElement.getElementById("Button1"), "click", toggleCssClassMethod);
I used to see only document.getElementById(id). So raised this question.Itmight be sound bad. But I am just kid in JS world.
No, the two are not the same. I think your confusion is probably coming from the common misconception that getElementById is a function only belonging to document. In fact, you can use getElementById on other DOM elements. Something like this works just fine:
document.getElementById("test").getElementById("test2")
http://jsfiddle.net/CNc2s/
Notice that the 2nd call of getElementById is being called on the DOM element returned by the first call. This will find an element with an id of test2 within an element with and id of test.
The reason you don't often see things like this is that ids must be unique within a document. So calling it on the document will get the same element as calling it on a containing element.
No, document is not an alias for Sys.UI.DomElement. This can be demonstrated with a quick experiment in the IE javascript console.
document.name = "hello";
console.log(Sys.UI.DomElement.name); // Prints undefined

is window.document.element a valid object?

Just as window and document objects in JS corresponds to window(?) and <body> elements in HTML, can you refer to more nested elements of the <body> simply by appending with dots(.)? (like window.document.p)
I haven't seen it anywhere but I don't know since I haven't seen it anywhere. It just seemed intuitive to me that nested elements in HTML be represented as nested objects in JavaScript instead of having to getElementByID but somehow this chain seems broken after window.document
Some nested elements can be accessed diretcly using
document.
, e.g.,
document.forms
, which is an array containing all forms on the page.
In general, however, you have either to traverse the dom tree using
element.children or element.childNodes
or access the element directly using methods like
document.getElementById()
document.querySelector()
an alike.
No that is not possible. You should just try it before you post.
You can access descendants of <body> by calling its getElementsByTagName method or the new querySelector and querySelectorAll methods.
You should check this documentation for more info - https://developer.mozilla.org/en/DOM/element
no, that isn't possible. but for some elements, there are special collections;
window.document.forms -> all form elements
window.document.images -> all image elements
window.frames -> all frame elements

Categories