33

I am new here (and new to JavaScript), so please excuse my super basic questions. I have a HTML page with different images that all share a class on it. By using getElementsByClassName, I get an array. I want to add an event listener to each of the cells in the array by using the .map() function.

This is what I have:

window.onload = function(){
var allImgs = document.getElementsByClassName("pft");

var newImgs = allImgs.map(
        function(arrayCell){
            return arrayCell.addEventListener("mouseover, functionName");
        }
    );
}; 

This keeps showing the error "allImgs.map is not a function" even when I change the inner function to something that doesn't include the event listener.

I have another version of this code where I just loop through the array cells within window.onload and add the event listener to each of them that way and it works. Why isn't the .map() function working? Can it not be used in window.onload?

Patsy Issa
  • 11,113
  • 4
  • 55
  • 74
JSn00b
  • 361
  • 1
  • 3
  • 6

5 Answers5

47

getElementsByClassName() returns an HTMLCollection not an Array. You have to convert it into a JavaScript array first :

allImgs = Array.prototype.slice.call(allImgs);

// or
allImgs = [].slice.call(allImgs);

// or (thanks @athari)
allImgs = Array.from(allImgs);

// or (thanks @eliaz-bobadilla)
allImgs = [...allImgs]
Mickäel A.
  • 9,012
  • 5
  • 54
  • 71
  • http://stackoverflow.com/questions/222841/most-efficient-way-to-convert-an-htmlcollection-to-an-array – baao Jul 28 '15 at 12:25
  • @ Flawyte Eek, it's not working for me yet. I'm probably overlooking something super basic. Here's what I got: `window.onload = function(){ var allImgs = document.getElementsByClassName("pft"); var newImgs = [].slice.call(allImgs); console.log(newImgs.typeof); newImgs.map( function(arrayCell){ return arrayCell.addEventListener("mouseover, flipOver"); } ); };` – JSn00b Jul 29 '15 at 18:24
  • @Flawyte sorry, the console log in the comment above just shows as "undefined". It doesn't seem to turn into an array? – JSn00b Jul 29 '15 at 18:35
  • @Flawyte Aaagh I found it myself sorry; I borked the addEventListener parenthesis contents (wrong quotation marks). Thanks! – JSn00b Jul 29 '15 at 19:01
  • 1
    @Flawyte Modern browsers support `Array.from` which is cleaner than `Array.prototype.slice.call`. – Athari Jun 21 '16 at 10:24
  • I use `Object.entries` `Object.entries(document.getElementsByTagName('button'))` from there u have the full power. – Stephan Ahlf Jun 28 '20 at 06:51
9

By using getElementsByClassName, I get an array.

No, you don't.

You get a live HTMLCollection. This is array-like but is not an array.

Since it is sufficiently array-like, you can apply the map method from a real array.

    var text_content = [].map.call(
      document.getElementsByClassName("sdf"),
      function (currentValue, index, collection) {
        return currentValue.innerHTML;
      }
    );
    console.log(text_content);
  <p class="sdf">foo</p>
  <p class="sdf"></p>
  <p class="sdf">bar</p>
  <p class="sdf"></p>
  <p class="sdf"></p>
          
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • 1
    Oh I see, thank you for clearing that up. so I could never use .map() on it because it's not a true array? But I can still get access to its cells the way I would get it from an array (as in htmlColls[i].addEventListener; etc)? – JSn00b Jul 28 '15 at 12:23
6

Another option would be to use map directly:

[].map.call(allImages, function() { ... });

However, what you are doing is better achieved with Array.prototype.forEach.

Rustem Mustafin
  • 957
  • 1
  • 11
  • 23
4

Compact syntax:

[...document.getElementsByClassName("pft")].map(arrayCell => arrayCell.addEventListener("mouseover", "functionName"))
Ari Singh
  • 1,228
  • 7
  • 12
0

var elms = document.querySelectorAll('.demo');
for(var i = 0; i < elms.length; i++) {
  var elm = elms[i];
  elm.onmouseleave = function() {
    this.style.color = "#000";
  }
  elm.onmouseover = function() {
    this.style.color = 'red';
  }
  
  
}
.demo {
  cursor:pointer;
}
<div>
  <p class="demo">paragraph one</p>
  <p class="demo">paragraph two</p>
  <p class="demo">paragraph three</p>
  <p class="demo">paragraph four</p>
  <p class="demo">paragraph five</p>
  <p class="demo">paragraph six</p>
</div>