I'm trying to set get id of all elements in an HTMLCollectionOf
. I wrote the following code:
var list = document.getElementsByClassName("events");
console.log(list[0].id);
for (key in list) {
console.log(key.id);
}
But I got the following output in console:
event1
undefined
which is not what I expected. Why is the second console output undefined
but the first console output is event1
?
This question is related to
javascript
dom
You want to change it to
var list= document.getElementsByClassName("events");
console.log(list[0].id); //first console output
for (key in list){
console.log(list[key].id); //second console output
}
On Edge
if(!NodeList.prototype.forEach) {
NodeList.prototype.forEach = function(fn, scope) {
for(var i = 0, len = this.length; i < len; ++i) {
fn.call(scope, this[i], i, this);
}
}
}
you can add this two lines:
HTMLCollection.prototype.forEach = Array.prototype.forEach;
NodeList.prototype.forEach = Array.prototype.forEach;
HTMLCollection is return by getElementsByClassName and getElementsByTagName
NodeList is return by querySelectorAll
Like this you can do a forEach:
var selections = document.getElementsByClassName('myClass');
/* alternative :
var selections = document.querySelectorAll('.myClass');
*/
selections.forEach(function(element, i){
//do your stuffs
});
Easy workaround that I always use
let list = document.getElementsByClassName("events");
let listArr = Array.from(list)
After this you can run any desired Array methods on the selection
listArr.map(item => console.log(item.id))
listArr.forEach(item => console.log(item.id))
listArr.reverse()
You can also do like this:
let elements = document.getElementsByClassName("classname");
for(let index in elements) {
if(index <= elements.length) {
console.log(elements[index]);
}
}
let elements = document.getElementsByClassName("classname");
for (let index in elements) {
if (index <= elements.length) {
console.log(elements[index]);
}
}
_x000D_
<div class="classname"> element 1 </div>
<div class="classname"> element 2 </div>
<div class="classname"> element 3 </div>
_x000D_
or
let elements = document.getElementsByClassName("classname");
for(let ele of elements) {
console.log(ele);
}
let elements = document.getElementsByClassName("classname");
for (let ele of elements) {
console.log(ele);
}
_x000D_
<div class="classname"> element 1 </div>
<div class="classname"> element 2 </div>
<div class="classname"> element 3 </div>
<div class="classname"> element 4 </div>
_x000D_
Alternative to Array.from
is to use Array.prototype.forEach.call
forEach:
Array.prototype.forEach.call(htmlCollection, i => { console.log(i) });
map: Array.prototype.map.call(htmlCollection, i => { console.log(i) });
ect...
As of March 2016, in Chrome 49.0, for...of
works for HTMLCollection
:
this.headers = this.getElementsByTagName("header");
for (var header of this.headers) {
console.log(header);
}
But it only works if you apply the following workaround before using the for...of
:
HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
The same is necessary for using for...of
with NodeList
:
NamedNodeMap.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
I believe/hope for...of
will soon work without the above workaround. The open issue is here:
https://bugs.chromium.org/p/chromium/issues/detail?id=401699
Update: See Expenzor's comment below: This has been fixed as of April 2016. You don't need to add HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator]; to iterate over an HTMLCollection with for...of
In ES6, you could do something like [...collection]
, or Array.from(collection)
,
let someCollection = document.querySelectorAll(someSelector)
[...someCollection].forEach(someFn)
//or
Array.from(collection).forEach(someFn)
Eg:-
navDoms = document.getElementsByClassName('nav-container');
Array.from(navDoms).forEach(function(navDom){
//implement function operations
});
I had a problem using forEach in IE 11 and also Firefox 49
I have found a workaround like this
Array.prototype.slice.call(document.getElementsByClassName("events")).forEach(function (key) {
console.log(key.id);
}
There's no reason to use es6 features to escape for
looping if you're on IE9 or above.
In ES5, there are two good options. First, you can "borrow" Array
's forEach
as evan mentions.
But even better...
Object.keys()
, which does have forEach
and filters to "own properties" automatically.That is, Object.keys
is essentially equivalent to doing a for... in
with a HasOwnProperty
, but is much smoother.
var eventNodes = document.getElementsByClassName("events");
Object.keys(eventNodes).forEach(function (key) {
console.log(eventNodes[key].id);
});
if you use oldder varsions of ES, (ES5 for example), you can use as any
:
for (let element of elementsToIterate as any) {
console.log(element);
}
You can't use for
/in
on NodeList
s or HTMLCollection
s. However, you can use some Array.prototype
methods, as long as you .call()
them and pass in the NodeList
or HTMLCollection
as this
.
So consider the following as an alternative to jfriend00's for
loop:
var list= document.getElementsByClassName("events");
[].forEach.call(list, function(el) {
console.log(el.id);
});
There's a good article on MDN that covers this technique. Note their warning about browser compatibility though:
[...] passing a host object (like a
NodeList
) asthis
to a native method (such asforEach
) is not guaranteed to work in all browsers and is known to fail in some.
So while this approach is convenient, a for
loop may be the most browser-compatible solution.
Update (Aug 30, 2014): Eventually you'll be able to use ES6 for
/of
!
var list = document.getElementsByClassName("events");
for (const el of list)
console.log(el.id);
It's already supported in recent versions of Chrome and Firefox.
Source: Stackoverflow.com