Vanilla JS - ES6: .map() is not a function

Viewed 1806

I am trying to refactor my for loop with .map() and ES6 and I am getting an error message stating ".map is not a function"

//basic tab function
function openContent(tabpages) {
  var page = document.getElementsByClassName("content");

  // for (i = 0; i < page.length; i++) {
  //   page[i].style.display = "none";
  // }
  page.map(page => (page.style.display = "none"));

  document.getElementById(tabpages).style.display = "flex";
}

Please point me to the right direction.

3 Answers

page is an HTMLCollection which is an Object not an Array. You can extract the object's keys to an array for mapping using Object.keys()

For example:

//basic tab function
function openContent(tabpages) {
  var page = document.getElementsByClassName("content");

  // for (i = 0; i < page.length; i++) {
  //   page[i].style.display = "none";
  // }
  Object.keys(page).map(idx => (page[idx].style.display = "none"));

  document.getElementById(tabpages).style.display = "flex";
}

As already mentioned, getElementsByClassName doesn't return an array, so you cannot call .map on it.

The simplest way to convert to an array would be to use Array.from:

var page = Array.from(document.getElementsByClassName("content"));

However, .map is not the right tool for what you are doing. .map creates a new array from the return values of the callback. But you don't actually intend to use that array.

You simply want to iterate over all elements. You can do this easily without converting the node list to an array, using for...of:

for (var page of document.getElementsByClassName("content")) {
  page.style.display = "none";
}

Given that you're iterating over the elements, and not — from the code you've posted — doing anything with the Array returned from Array.prototype.map() Id suggest using document.querySelectorAll() and NodeList.prototype.forEach() to iterate over that NodeList:

document.querySelectorAll('.content').forEach( (page) => page.style.display = 'none' );

Although I'd also recommend using a class to hide the elements, rather than modifying the inline-styles directly:

document.querySelectorAll('.content').forEach( (page) => page.classList.add('hidden') );

Obviously that does require a CSS definition for the hidden class-name.

References:

Related