21

I am trying to use the js document.getElementsByClassName to locate an html element, which is actually the header of a table.

For the following codes:

console.log(document.getElementsByClassName('gtableheader'));

From the Firebug, I can see it log a HTMLCollection, and when I click it, it shows:

-> 0         tr.gtableheader
   length    1

So it do locate the element I want.

But when I using:

console.log(document.getElementsByClassName('gtableheader').length);

Then output is 0. That's so weird, any ideas about this?

chrisTina
  • 2,298
  • 9
  • 40
  • 74
  • 1
    Can we see your HTML code? Are you creating the element dynamically? – showdev Nov 12 '15 at 20:12
  • 1
    Are you calling it **after** the element in the document, e.g. after the load event? – RobG Nov 12 '15 at 20:43
  • Possible duplicate of [document.getElementsByClassName('name') has a length of 0](http://stackoverflow.com/questions/24337200/document-getelementsbyclassnamename-has-a-length-of-0) – showdev Nov 12 '15 at 22:12

6 Answers6

22

That's because the getElementsByClassName returns a live collection. the length property of the object is 0 because at that point of time there is no element with that className in the DOM. Since the console shows the live representation of an object, it shows all the matching elements when the elements are added to the DOM.

DOM parser parses the documents from top to bottom, when it reaches to a tag, it parses it and adds the DOM representation of it (an instance of HTMLElement interface) to the Document Object Model. You should either move the script tag to the end of body tag or listen to DOMContentLoaded event which is fired when the initial HTML document has been completely loaded and parsed.

Ram
  • 143,282
  • 16
  • 168
  • 197
  • 2
    "That's because the getElementsByClassName returns a **_LIVE_** collection" should be written with h1 tag font. It is such an important fact to know. – RBT May 22 '21 at 14:55
7

Use this to make it work

window.addEventListener("load", function(event) {
    console.log(document.getElementsByClassName('gtableheader').length);
});
6

Using getElementsByClassName() will return all the elements with that class name in a document as a NodeList. This object represents a collection of nodes that can be accessed by index numbers, which starts in 0. In order to access the elements in the NodeList you will have to use a loop.

When you console.log(document.getElementsByClassName('gtableheader').length); you see 0 because when you run it there is no element with class gtableheader. You are able to see the items in the console because document.getElementsByClassName() returns a live collection that is updated when the new elements are added.

As well, in the code you are using and the length is 0, you can use the code below to access the class name.

document.getElementsByClassName('gtableheader')[0].style.color="red";

If you want to access all the elements in the class you can use a for loop.

var x = document.getElementsByClassName('gtableheader');
for (var i = 0; i < x.length; i++) {
    x[i].style.color = "red";
}

More information: http://www.w3schools.com/jsref/met_document_getelementsbyclassname.asp

Victor Luna
  • 1,746
  • 2
  • 17
  • 36
  • 21
    this doesn't seem to answer the question. You also reference the length property of the nodeList returned by `getElementsByClassName` -- you just read it off the variable `x` you assigned the result to. When I run `document.getElementsByClassName('question').length` against this very page, which only has a single element with that class, the result is 1. So, you don't provide an answer to why the length property in the OP's question returns 0. – Val Nov 12 '15 at 21:25
  • 4
    Yes, actually, the real problem is that I try to access the `element` before it is loaded, that's why the length is `0`. – chrisTina Nov 13 '15 at 14:32
  • Another problem is that `element` does not have a `style` property. It works, but the IDE keeps complaining that it should be `HTMLElement`. How to solve this? – Kokodoko Jun 01 '18 at 10:29
  • thank, just more the code inside document ready it work. but it is weird in a logic way var xyz= document.getElementsByClassName('xyz'); console.log(xyz); console.log(xyz.length);. I assign to get the group elements first, then read the length of the variable but it still return 0. it is javascript... :) – Võ Minh Jan 30 '19 at 04:41
  • Does document.getElementsByClassName create a new HTMLCollection or simply return an existing one? – SuperSim135 Jul 26 '21 at 21:11
5

I had a similar problem, but the other answers here didn't lead to my solution. I eventually realized that at the time my code was running, the DOM wasn't yet fully constructed, thus the empty array. What I was seeing in the console, a populated array, was what existed after the DOM was fully formed and the script was complete.

What worked for me was to wrap the code that needed the array within a MutationObserver and set it to watch the hard-coded div containing the sections that would be dynamically generated (see this StackOverflow answer and the MDN documentation).

Try this:

var divArray = document.getElementById('hardCodedContainer');

var observer = new MutationObserver(function(){
   console.log(document.getElementsByClassName('gtableheader').length);
   console.log(document.getElementsByClassName('gtableheader'));
};

observer.observe(divArray, { attributes: false, childList: true, subtree: true });

// When you've got what you need, you should call this function to trigger a disconnect 
function classesFound(){
   observer.disconnect();
};
jamesthe500
  • 341
  • 1
  • 7
  • 10
0

I had this problem asking for the elements just after its dynamic creation, fixed with setTiemout()

martindhx
  • 13
  • 2
  • 3
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 15 '22 at 20:46
0

Simply place your <script> tag before </body>

If <script> tag is not added at end of the <body> tag, DOM may not be ready by that time, thus preventing javascript to work on it, leading to unknown behaviors