Traversing the DOM with filter(), map(), and arrow functions

Today I was trying to iterate through all the DOM elements with a certain class on the page, pull their attributes into an object, and compile these objects into an array. Sounds pretty simple, right? Apparently not. I ran into some trouble, so I wanted to write this to help others in similar situations.

The naïve (wrong ) way

var elements = document.getElementsByClassName("bgflag"); 
var BgFlags = [] //Array of objects of info about the elements
for (i in elements){ //assemble our info objects
var flag = {
height: elements[i].offsetTop,
bgsrc: elements[i].dataset.bgsrc,
bgcolor: elements[i].dataset.bgcolor,
size: elements[i].dataset.size,
name: elements[i].id,
image: parseInt(elements[i].dataset.image)
}
BgFlags.push(flag);
if(flag.name == "defaultFlag"){
defaltFlag = flag //global variable
}
}

The boring way

Per the NodeList doc linked above:

for (var i = 0; i < myNodeList.length; ++i) {
var item = myNodeList[i]; // Calling myNodeList.item(i) isn’t necessary in JavaScript
}
var list = document.querySelectorAll( ‘input[type=checkbox]’ );
for (var item of list) {
item.checked = true;
}

The fun(ctional) way

In college, I took a class that taught functional programming. It was the most fun I’ve ever had programming.

  • Array.prototype.filter(fn) calls fn on each item in the array amd assembles a new array of only the elements from the original array for which fn returned true.
var timesTwo = num => num * 2;
// if you have more than one argument, you need () around them
// equivalent to
var timesTwo = num => { return num * 2 }
//equivalent to
var double = function(num){ return num * 2;}
  • The body of an arrow function can be an expression or a block
  • If the body is an expression, the result of the expression will be returned
  • If the body is a block, it’s basically more compact syntax for an anonymous function*
  • *It’s not relevant here, but arrow functions handle context and this very differently. Read the doc if it matters to you.
var elements = document.getElementsByClassName("bgflag");
elements = Array.from(elements); //convert to array
BgFlags = elements.map(element =>
({
height: element.offsetTop,
bgsrc: element.dataset.bgsrc,
bgcolor: element.dataset.bgcolor,
size: element.dataset.size,
name: element.id,
image: parseInt(element.dataset.image)
})
);
defaultFlag = BgFlags.filter(flag => flag.name == "defaultFlag")[0]; //we need the [0] because filter() returns an array
var elements = document.getElementsByClassName("bgflag");
BgFlags = Array.prototype.map.call(elements,
element =>
({
height: element.offsetTop,
bgsrc: element.dataset.bgsrc,
bgcolor: element.dataset.bgcolor,
size: element.dataset.size,
name: element.id,
image: parseInt(element.dataset.image)
})
);
defaultFlag = BgFlags.filter(flag => flag.name == "defaultFlag")[0]; //we need the [0] because filter() returns an array

Written by

Decent programmer, mediocre poet. Currently at Axosoft

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store