I’ve been prototyping some form input interactions for my current project, and now that I’ve got some basic examples working I wanted to refactor the code to get rid of jQuery as a dependency and improve performance.
Using jQuery this sort of event-binding is pretty straightforward:
However, this code doesn’t work. Why?
So let’s refactor the code to only attach the event listener to the first element (the one with a  position) in the array-like object.
Unfortunately our code fails again: the error in the console is “inputs.forEach is not a function”. This is because the the .getElementsByClassName() method doesn’t return an array (which has a .forEach() method) — it returns an array-like object. Array-like objects:
- have: indexed access to elements and the property length that tells us how many elements the object has.
- does not have: array methods such as push, forEach and indexOf.
Two examples of array-like objects is the result of the DOM method document.getElementsByClassName() (many DOM methods return array-like objects) and the special variable arguments.
Looping Through an Array-Like Object (The Old Way)
We need to do two things to loop through the array-like object returned by the .getElementsByClassName() method.
- Get access to the Array.prototype.forEach() method available for real arrays,
- Use the Function.prototype.call() method to assign each element in the array-like object to the this value in the .forEach method
Doing so looks like this:
Success! See the code on Codepen.
Update: Looping Through an Array-Like Object (The New Way)
I‘d make a note of ES6’s Array.from(), which makes an array from an array-like object. You can call it like Array.from(items).forEach(…)
Also, don’t forget the shorthand for Array.prototype — an Array! You can write.forEach.call(…) if you don’t mind instantiating a new array.