DEV Community

Pablo Hoc
Pablo Hoc

Posted on

Selecting multiple DOM elements with destructuring and map

If you are working with vainilla JS and manipulating DOM elements, I'm sure earlier than later you found yourself with code like this:

const sendButton = document.getElementById('send-btn');
const discountPopUp = document.getElementById('discount-popup');
const messageInput = document.getElementById('message');
const calculateButton = document.getElementBy('calculate-btn');
// dozens of elements more

Please don't take this example too serious. I'm not saying this is good code or even these are good named constants and ids. I just wanted to show that this code can be simplified using some awesome ES6 features: map and destructuring. We could do the following:

const [sendButton, discountPopUp, messaInput, calculateButton] = ['send-btn', 'discount-popup', 'message', 'calculate-btn'].map(id => document.getElementById(id));

Why does this work? Let's go step by step.

First, map is an Array method that takes a function as callback. Then, for each element of the array, executes the callback, pasing the element as a parameter of the callback. The return of that callback is added to a new array. So, as the name says, map maps the elements of an array to a new array, passing each element through a function.

For example,

const numbers = [1, 2, 3, 4];
const doubles = numbers.map(number => number * 2);
console.log(doubles); // [2, 4, 6, 8];

map here is mapping each number to its double, and storing it in the new array doubles.

The callback is written as an arrow function. The arrow function doesn't need to declare the reserver word return if the only thing that does is returning some value. If that is not too clear, we could rewrite the arrow function like:

const doubles = numbers.map((number) => { return number * 2});

but as you can see, the first one is more concise. Even more, we don't need the constant numbers, we can use map directly on the array:

const doubles = [1, 2, 3, 4].map(number => number * 2);

Awesome, rigth?, So, back to our example, we had:

const elements = ['send-btn', 'discount-popup', 'message', 'calculate-btn'].map(id => document.getElementById(id));

Here we have an array with ids, and map is mapping each of those strings to a HTML element, since the callback takes an id and returns a HTML element with that id. Those elements are stored in a new array, elements.

But that is not very helpful. If now we want to use the element with id 'message', we need to retrieve it like:

elements[2]

This doesn't say much. Imagine using it 100 lines later. What the heck elements[2] is?

Of course we can avoid this storing it in a variable, but that take us back to where we begin.

const elements = ['send-btn', 'discount-popup', 'message', 'calculate-btn'].map(id => document.getElementById(id));

const sendButton = elements[0]
const discountPopUp = elements[1];
const messageInput = elements[2];
const calculateButton = elements[3];
// dozens of elements more

Which is not very practical. Instead of that, we can destructure the array which map returns. You can image destructuring an array as taking each of its elements and storing it in a variable.

For example:

let [a, b, c] = [0, 1, 2];
console.log(a); // 0
console.log(b); // 1
console.log(c); // 2

Each element of the array on the right is stored in its respective variable, in order. The first element of the array in the right is stores in the first variable of the left, and so on.

So, knowing this, we can finally end where we started.

const [sendButton, discountPopUp, messaInput, calculateButton] = ['send-btn', 'discount-popup', 'message', 'calculate-btn'].map(id => document.getElementById(id));

Top comments (1)

Collapse
 
anduser96 profile image
Andrei Gatej

Great tip!

Something I always use when writing vanilla js:

const $ = document.querySelector.bind(document);

const elemById = $(β€œ#an-id”);