5

In the below code,

<!DOCTYPE html>
<html>
    <head>
        <title>Hide odd rows</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <div style="background-color:#8F9779;width:200px;height:30px;">
        </div>
        <hr style="width:200px" align="left">
        <table border="1" >
            <tr class="hide" >
                <td width="40" height="20">row 1</td>
            </tr>
            <tr>
                <td width="40" height="20">row 2</td>
            </tr>
            <tr class="hide">
                <td width="40" height="20">row 3</td>
            </tr>
            <tr>
                <td width="40" height="20">row 4</td>
            </tr>
            <tr class="hide">
                <td width="40" height="20">row 5</td>
            </tr>
        </table><br>
        <button type="button" name="HideRows">Hide Odd Rows</button>
        <script type="text/javascript" src="hideOddRows.js"></script>
    </body>
</html>

/* hideOddRows.js */
document.querySelector('[name=HideRows]').onclick = hideRows;

function hideRows(){
    var elements = document.getElementsByClassName('hide');
    elements.forEach(function(element){
        element.style.visibility = "hidden";
    });
    return true;
}

As per debugging, callback function for each element of elements array is not executing on click event.

I consider elements as keyed collection, as shown below..

enter image description here

--

How to resolve this error?

overexchange
  • 15,768
  • 30
  • 152
  • 347
  • `elements` has `nodelist` and `forEach` does not work with `nodelist`. Try `[].forEach.call(elements,function(item){});` – Rayon Dec 16 '15 at 04:11

4 Answers4

9

forEach is not included in the prototype of the array-like HTMLCollection object returned by getElementsByClassName.

An HTMLCollection instance is array-like, in that you can access elements by indexes, but it does not include all of the methods of an array, as you have discovered with forEach.

You can however manually call the method on the object by accessing the method from the Array prototype.

var elements = document.getElementsByClassName('hide');
Array.prototype.forEach.call(elements, function(element){
    element.style.visibility = "hidden";
});
Alexander O'Mara
  • 58,688
  • 18
  • 163
  • 171
  • What is the story about `return true`? You didn't use it. Is it a must to say `return true` in callback and event handlers? Can't I say `return 1` or `return 23`? – overexchange Dec 16 '15 at 04:42
  • @overexchange In your case, it means allow the default behavior. I excluded it from my sample, as it's not directly related to the `forEach` issue. See this answer for more info: http://stackoverflow.com/a/128966/3155639 – Alexander O'Mara Dec 16 '15 at 04:44
2

The forEach method is for arrays. It's not working because .getElementsByClassName() returns an HTMLCollection.

To work around this, use:

var elements = document.getElementsByClassName('hide');
Array.prototype.forEach.call(elements, function(element){
    element.style.visibility = "hidden";
});

or shorter:

var elements = document.getElementsByClassName('hide');
[].forEach.call(elements, function(element){
    element.style.visibility = "hidden";
});
Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
1

you can convert elements to an array and then call forEach().

 var elements = document.getElementsByClassName('hide');
 elements = Array.prototype.slice.call(elements,0);
    elements.forEach(function(element){
        element.style.visibility = "hidden";
    });

fiddle :https://jsfiddle.net/assx7hmh/

Ramanlfc
  • 8,283
  • 1
  • 18
  • 24
0

Base on your code, here is my solution:

function hideRows(){
  var elements = document.getElementsByClassName('hide');
  for(var key in elements) {
    if(elements.hasOwnProperty(key))
      elements[key].style.visibility = "hidden";
  }
  return true;
}

You just need to loop through object because forEach just accept array.

omgpwned
  • 147
  • 8