Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I use Array.forEach on a collection of Javascript elements? [duplicate]

I'm building an app with Babel/ES6. I want to disable all form elements for a view-only version of it, so I did this:

let form = document.getElementById('application-form')
let elements = form.elements

I expected to be able to do this, instead of using a regular old for loop (which did work):

elements.forEach((el) => {
    el.disabled = true
})

but I got TypeError: elements.forEach is not a function

The strange thing is if I console.log(elements) in the Chrome dev console it exactly like an array with a bunch of input objects. It doesn't display with the Object notation for objects, and all of the keys are integers. I'm thinking it's some sort of pseudo array, but I wouldn't even know how to find that out.

EDIT: short answer it's not an array it's an HTMLCollection. see Why doesn't nodelist have forEach?


*UPDATE*

Per this answer, nodelist now has the forEach method!

like image 461
inostia Avatar asked Sep 30 '16 17:09

inostia


People also ask

Can we use forEach for array in JavaScript?

The forEach method is also used to loop through arrays, but it uses a function differently than the classic "for loop". The forEach method passes a callback function for each element of an array together with the following parameters: Current Value (required) - The value of the current array element.

Does forEach make a copy of the array?

forEach() does not make a copy of the array before iterating.

Does forEach work on objects JavaScript?

JavaScript's Array#forEach() function lets you iterate over an array, but not over an object. But you can iterate over a JavaScript object using forEach() if you transform the object into an array first, using Object. keys() , Object. values() , or Object.

What can I use instead of forEach in JavaScript?

map() allocates memory and stores return values. forEach() throws away return values and always returns undefined . forEach() will allow a callback function to mutate the current array. map() will instead return a new array.


1 Answers

You can. You just can't use it like that, because there is no forEach property on the HTMLFormControlsCollection that form.elements gives you (which isn't an array).

Here's how you can use it anyway:

Array.prototype.forEach.call(form.elements, (element) => {
    // ...
});

Or on modern browsers you can make use of the fact that the underlying HTMLCollection is iterable even though it doesn't have forEach:

// `for-of`:
for (const element of elements) {
    // ...do something with `element`...
}

// Spreading into an array:
[...elements].forEach((element) => {
    // ...do something with `element`...
});

That won't work on obsolete browsers like IE11 though.

There's also Array.from (needs a polyfill for obsolete browsers):

Array.from(elements).forEach((element) => {
    // ...
});

For details, see the "array-like" part of my answer here.

like image 107
6 revs, 2 users 99% Avatar answered Oct 03 '22 21:10

6 revs, 2 users 99%