0

In Javascript, I get the elements of a given class using:

A = document.getElementsByClassName("someclass");
> A contains elements e1, e2, e3, e4

Then, I change the class of one of these elements:

document.getElementById("e2").className = "anotherclass";

To my great surprise, the array A has been automatically changed in the process !!

> A contains elements e1, e3, e4

I thought that the array returned by getElementsByClassName would stay the same now that is was assigned.

  • How is that possible? Is it an intended behaviour?
  • Is there a simple way to change that?

Here is a JSfiddle.

Note that this is also true for getElementById.

fffred
  • 596
  • 4
  • 19
  • FYI, if you don't want the returned `nodeList` to be live (as the answers have explained), you can switch to using `document.querySelectorAll()` which returns a static `nodeList` and has better browser support than `document.getElementsByClassName()`. – jfriend00 May 02 '14 at 23:36
  • @jfriend00 - But wouldn't changing the class still be updated in the non-live nodelist. I answered the same thing, but then tested it **http://jsfiddle.net/USmsH/2/**, and it seems a non-live nodelist is only static to the extent of actual DOM changes, as in adding/removing children etc. – adeneo May 02 '14 at 23:39
  • @adeneo: Your demo shows all four elements in the list (testing in Firefox). – cookie monster May 02 '14 at 23:45
  • @adeneo - A non-live nodeList is nothing more than a static list of nodes. It will not change. See the console in here: http://jsfiddle.net/jfriend00/nDkga/ – jfriend00 May 02 '14 at 23:45
  • Of course it shows all four elements in the console, but if you look at the question the OP is changing the class, and it's updated in the live nodeList, but that happens in a non-live nodeList as well. The console shows all four elements, and the class on the second one *is* changed. If you add or remove elements, that would be an actual change to the DOM structure, which is not reflected in the non-live nodeList, hence my comment above. – adeneo May 02 '14 at 23:49

2 Answers2

3

This is because A is not an Array. getElementByClassName returns an HTMLCollection which is live-updated due to changes in the document.

The easiest way to convert an array-like object into an array would be to do this:

var A = ...

// With ES5 code
var A_array = Array.prototype.slice.call(A);

// With ES6 code
var A_array = Array.from(A);

Or you can get NodeList instead via querySelectorAll, which won't live-update.

var A = document.querySelectorAll('.someclass');
loganfsmyth
  • 156,129
  • 30
  • 331
  • 251
1

These functions return live NodeLists. This means that they are automatically updated to reflect the current contents of the DOM.

See the NodeList documentation.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Not all `nodeList`s are live. `document.querySelectorAll()` returns a non-live `nodeList`. You have to consult the specific function to see whether it returns a live or non-live `nodeList`. – jfriend00 May 02 '14 at 23:37
  • I know that. It says it in the documentation I linked to. – Barmar May 02 '14 at 23:42
  • My point was that you have to refer to the doc for the function you're using, not the `nodeList` doc to know whether your `nodeList` is live or not. In this case, the doc for `getElementsByClassName()` would have been more relevant in my opinion. – jfriend00 May 02 '14 at 23:48
  • Hmm, MDN documentation of getElementsByClassName doesn't mention that it's a live NodeList. w3fools doesn't mention it, either, but I wouldn't link to them even if they did. Got a better reference that I can add to my answer? – Barmar May 02 '14 at 23:53
  • That's a miss that the MDN doc doesn't explain it. I don't have a better MDN-style reference. – jfriend00 May 02 '14 at 23:56