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.

In order to trigger the animations correctly, I need the Javascript to run on two events: when the input receives focus, and when the input loses focus (and to test whether or not the input is empty when it does).

Using jQuery this sort of event-binding is pretty straightforward:

Shouldn’t be too hard to convert this to plain ol’ Javascript, right?

However, this code doesn’t work. Why?

Differences between jQuery and Javascript

Both $(‘.text-input’) and .getElementsByClassName(‘text-input’) select all the HTML elements with the given class, and both return array-like objects, but a minor difference between the two is that the Javascript selector returns a NodeList. The main difference is that the jQuery .on() method can “Attach an event handler function for one or more events to the selected elements” whereas the .addEventListener() method can only operate on a single target.

So let’s refactor the code to only attach the event listener to the first element (the one with a [0] position) in the array-like object.

It works- but to extend it to each element in the array-like object requires us to refactor the code to loop through and attach an event listener to each element in the array-like object. We’ll use Javascript’s .forEach() method to run a function once for each element 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)

A commenter on Reddit’s /r/webdev board mentioned that ES6 includes a new method, Array.from(), which makes the process of creating an array from an array-like object a lot simpler.