0

I am trying to loop over an HTMLCollection but it appears as though the break-condition is met before the loop is entered. Furthermore, when I print the HTMLCollection to console, it returns the HTMLCollection and I can see that there are elements in it, however, when I try to print any of its indices, it returns undefined

Here is the code:

var applicant_elements = document.getElementsByClassName('applicant');
console.log(applicant_elements); // returns the HTMLCollection
                                 // with length of 8
                                 // and valid elements
console.log(applicant_elements[0]); // returns undefined
for (var i = 0; i < applicant_elements.length; i++) {
    console.log('hello'); // this is never logged
}

Here is what is logged from the above code:

console log screenshot

I should also state that I am running the following code within an angularJS controller. Not sure if that changes anything, but I feel like it shouldn't

Pop-A-Stash
  • 6,572
  • 5
  • 28
  • 54
MattR
  • 127
  • 2
  • 11
  • Is that *really* what your JavaScript looks like? Exactly that? – Pointy Aug 27 '18 at 19:15
  • The script is most likely placed _above_ the elements in the DOM or before they are available in the DOM. Log the length of the collection and it will be zero. – Andreas Aug 27 '18 at 19:17
  • Yes, exactly, minus the comments. That makes sense @Andreas. Indeed, the length is 0. But why would the console log the Collection with all the elements? – MattR Aug 27 '18 at 19:27

2 Answers2

3

As mentioned in this answer, console.log() calls are not necessarily immediate in different browsers. document.getElementsByClassName returns a reference to a live HTMLCollection. This means that any changes to the DOM will automatically be reflected in the collection, and thus when the call to console.log is finally resolved, you'll see all of the associated nodes in the output. However, reference to applicant_elements[0] is not a live reference - it is resolved at the given point in time and thus will not change from being undefined.

To summarize: your HTMLCollection is likely empty right after the query, but your code adds elements before the console.log() call is resolved (e.g. before returning from the function).

Lauri Piispanen
  • 2,067
  • 12
  • 20
  • Ah. Okay, that makes sense. If I put the code above in ` – MattR Aug 27 '18 at 19:33
  • It's hard/impossible to say without having more context. From what I can gather, it looks like you're developing an Angular application, so it is definitely possible that those nodes are being rendered asynchronously, whereas the script tags are executed immediately when the HTML is being parsed. – Lauri Piispanen Aug 27 '18 at 19:42
1

The fun thing with getElementsByClassName is it is a LIVE html collection. So that means things get added and removed from it. And add in the fact you have lazy evaluation in the console, makes for fun debugging.

var x = document.getElementsByClassName("test");

console.log("before", x.length);  // will show 0
console.log(x);  // In browser console will show one item because of code below

var d = document.createElement("div");  //create an element to add
d.classList.add("test")  // our class we are looking for
document.body.appendChild(d); // add it

console.log("after", x.length);  // will show 1
console.log(x);  //will show 1 item
epascarello
  • 204,599
  • 20
  • 195
  • 236