Iterating over result of getElementsByClassName using Array.forEach
No, it's not an array. As specified in DOM4, it's an HTMLCollection
(in modern browsers, at least. Older browsers returned a NodeList
).
In all modern browsers (pretty much anything other IE <= 8), you can call Array's forEach
method, passing it the list of elements (be it HTMLCollection
or NodeList
) as the this
value:
var els = document.getElementsByClassName("myclass");
Array.prototype.forEach.call(els, function(el) {
// Do stuff here
console.log(el.tagName);
});
// Or
[].forEach.call(els, function (el) {...});
If you're in the happy position of being able to use ES6 (i.e. you can safely ignore Internet Explorer or you're using an ES5 transpiler), you can use Array.from
:
Array.from(els).forEach((el) => {
// Do stuff here
console.log(el.tagName);
});
How to correctly iterate through getElementsByClassName
According to MDN, the way to retrieve an item from a NodeList
is:
nodeItem = nodeList.item(index)
Thus:
var slides = document.getElementsByClassName("slide");
for (var i = 0; i < slides.length; i++) {
Distribute(slides.item(i));
}
I haven't tried this myself (the normal for
loop has always worked for me), but give it a shot.
Using forEach on an array from getElementsByClassName results in “TypeError: undefined is not a function”
That's because document.getElementsByClassName
returns a HTMLCollection, not an array.
Fortunately it's an "array-like" object (which explains why it's logged as if it was an object and why you can iterate with a standard for
loop), so you can do this :
[].forEach.call(document.getElementsByClassName('myClass'), function(v,i,a) {
With ES6 (on modern browsers or with Babel), you may also use Array.from
which builds arrays from array-like objects:
Array.from(document.getElementsByClassName('myClass')).forEach(v=>{
or spread the array-like object into an array:
[...document.getElementsByClassName('myClass'))].forEach(v=>{
Unable to loop through HTMLCollection with forEach
HTMLCollection is an array-like object but it does not have forEach
method.
There are multiple ways you can iterate it with;
e.g.
Create an array out of it;
Array.from(toggleButton).forEach((el) =>
el.addEventListener("click", (event) => {
const card = event.target.parentElement.querySelector(".director__card");
card.classList.toggle("open");
})
);
Use for..of
for (let item of toggleButton) {
item.forEach((el) =>
el.addEventListener("click", (event) => {
const card = event.target.parentElement.querySelector(".director__card");
card.classList.toggle("open");
});
);
}
Or, just for
loop.
for (let i = 0, len = toggleButton.length; i < len; i++) {
toggleButton[i].forEach((el) =>
el.addEventListener("click", (event) => {
const card = event.target.parentElement.querySelector(".director__card");
card.classList.toggle("open");
});
);
}
Toggle classes with getElementsByClassName inside a foreach loop with Javascript
Lots of ways to do this. Ensure that you are adding event listeners to all the divs and not just the first one.
Looking at your current code you can follow this approach.
this
inside event listener belongs to the element that triggered the event. So when we do this.getElementsByClassName
we are querying for classes only inside that particular element.
getElementsByClassName
does not return an array. It returns a collection which is array-like. To use forEach()
on that array-like object converting it into an array is required. Using the ...
(spread) operator to convert the collection into an array.
[...document.getElementsByClassName('read-more-div')].forEach(x => x.addEventListener('click', function() {
this.getElementsByClassName('read-more-btn1')[0].classList.toggle('hide');
this.getElementsByClassName('read-more-btn2')[0].classList.toggle('hide');
return false
}));
body {
background-color: #000000;
color: #ffffff;
}
p,
button {
background-color: #000000;
color: #ffffff;
border: none;
padding: 0;
margin: 0;
}
.read-more-btn1 {
color: #888888;
cursor: s-resize;
}
.read-more-btn2 {
cursor: n-resize;
}
.read-more-btn1:hover {
color: #ffffff;
}
.hide {
display: none;
}
<div>Project A
<div class="read-more-div">
<button class="read-more-btn1">Read more...</button>
<p class="read-more-btn2 hide">Toggle this project text</p>
</div>
</div>
<div>Project B
<div class="read-more-div">
<button class="read-more-btn1">Read more...</button>
<p class="read-more-btn2 hide">Toggle this project text</p>
</div>
</div>
<div>Project C
<div class="read-more-div">
<button class="read-more-btn1">Read more...</button>
<p class="read-more-btn2 hide">Toggle this project text</p>
</div>
</div>
Using entries() in a for-of loop, iterating over an HTMLCollection
Entries method is available for arrays. However, getElementsByClassName
does not return an array. Instead it returns an HTMLCollection
. You need to first convert it into array. There are two ways you can do that:
- Using
Array.prototype.slice
function toArray(arr) {
return Array.prototype.slice.call(arr);
}
toArray(document.getElementsByClassName('foo'));
- Using ES6 spread
function toArray(arr) {
return [...arr];
}
toArray(document.getElementsByClassName('foo'));
Related Topics
JavaScript Implementation of Gzip
How to Use Setinterval and Clearinterval
JavaScript - Track Mouse Position
Is There a Case Insensitive Jquery :Contains Selector
Synchronized Scrolling Using Jquery
Generate Dynamic CSS Based on Variables Angular
Event Listener on a CSS Pseudo-Element, Such as ::After and ::Before
Nodejs and Socket.Io, Is It Pure JavaScript
Change the Selected Value of a Drop-Down List with Jquery
Getting JavaScript Object Key List
Sleep in JavaScript - Delay Between Actions
Tainted Canvases May Not Be Exported
Null-Safe Property Access (And Conditional Assignment) in Es6/2015
Modify a CSS Rule Object with JavaScript
Better Way to Prevent Browser Caching of JavaScript Files
What Is the Best Method to Reduce the Size of My JavaScript and CSS Files