getElementsByClassName doesn't work, but getElementById does?

10,807

Solution 1

You should use getElementsByClassName() or querySelectorAll() to collect all div.Klass (Klass being an arbitrary name). The following Snippet uses querySelectorAll() details are commented in source.

SNIPPET

function toggleDiv() {
  // Collect all .image into a NodeList
  var xs = document.querySelectorAll(".image");
  // Declare i and qty for "for" loop
  var i, qty = xs.length;
  // Use "for" loop to iterate through NodeList
  for (i = 0; i < qty; i++) {
    // If this div.image at index [i] is "none"...
    if (xs[i].style.display === 'none') {
      // then make it "block"... 
      xs[i].style.display = 'block';
    } else {
      // otherwise set display to "none"
      xs[i].style.display = 'none';
    }
  }
}
#firstimage {
  width: 100px;
  height: 100px;
  padding: 0px 0;
  text-align: center;
  background-color: green;
  margin-top: 20px;
  color: white;
}
#secondimage {
  width: 100px;
  height: 100px;
  padding: 0px 0;
  text-align: center;
  background-color: blue;
  margin-top: 20px;
  color: white;
}
#thirdimage {
  width: 100px;
  height: 100px;
  padding: 0px 0;
  text-align: center;
  background-color: red;
  margin-top: 20px;
  color: white;
}
<button onclick="toggleDiv()">Try me</button>

<div id="firstimage" class='image'>
  DIV element.
</div>

<div id="secondimage" class='image'>
  A second DIV element.
</div>

<div id="thirdimage" class='img'>
  A third DIV element.
</div>

In this function, just using an "array-like" object such as a NodeList demonstrated in the Snippet above. An array would be used in the same manner as it is in the Snippet. Should you want to do more advanced processing of the divs such as running a function on each of them and returned then converting an "array-like" object into an array would be necessary to run methods like map, forEach, slice, etc.

Solution 2

document.getElementsByClassName returns an array of elements, so you would need to iterate through that array and operate on each element within that loop.

Share:
10,807
Admin
Author by

Admin

Updated on August 15, 2022

Comments

  • Admin
    Admin almost 2 years

    I've written a script, it's goal is to stop displaying images one and two, while allowing image 3 to remain displayed and move into their place. It works fine when I use div Id's instead of div Classes, but I would prefer to use div classes so I can group the elements like this:

     function myFunction() {
         var y = document.getElementsByClassName("firstimage secondimage");
         if (y.style.display === 'none') {
               y.style.display = 'block';
         } else {
               y.style.display = 'none';
         }
     }
    

    rather than this (in order to save space should I choose to include more elements):

     function myFunction() {
         var x = document.getElementById("firstimage");
         if (x.style.display === 'none') {
              x.style.display = 'block';
         } else {
              x.style.display = 'none';
         }
    
         var y = document.getElementById("secondimage");
         if (y.style.display === 'none') {
              y.style.display = 'block';
         } else {
              y.style.display = 'none';
         }
    }
    

    I thought that just changing the div id's to div classes, and the #imagenumber's to .imagenumber's (in addition to the change in the javascript I described above) would work but the script stops working when I do. I need the script to function in the same way that the code I am pasting below does, but with div classes instead of div Id's. Please tell me where I am going wrong.

    CSS:

    #firstimage {
        width: 100px;
        height: 100px;
        padding: 0px 0;
        text-align: center;
        background-color: green;
        margin-top:20px;
        color: white;
    }
    
    #secondimage {
        width: 100px;
        height: 100px;
        padding: 0px 0;
        text-align: center;
        background-color: blue;
        margin-top:20px;
        color: white;
    }
    
    #thirdimage {
        width: 100px;
        height: 100px;
        padding: 0px 0;
        text-align: center;
        background-color: red;
        margin-top:20px;
        color: white;
    }
    

    HTML:

    <button onclick="myFunction()">Try me</button>
    
    <div id="firstimage">
        DIV element.
    </div>
    
    <div id="secondimage">
        A second DIV element.
    </div>
    
    <div id="thirdimage">
        A third DIV element.
    </div>
    

    Javascript:

    function myFunction() {
         var x = document.getElementById("firstimage");
         if (x.style.display === 'none') {
              x.style.display = 'block';
         } else {
              x.style.display = 'none';
         }
    
         var y = document.getElementById("secondimage");
         if (y.style.display === 'none') {
              y.style.display = 'block';
         } else {
              y.style.display = 'none';
         }
    }
    
  • Sterling
    Sterling almost 8 years
    You may also be interested in document.querySelectorAll
  • brk
    brk almost 8 years
    It returns an array-like object of all child elements which is different from array of elements
  • enhzflep
    enhzflep almost 8 years
    @user2181397 - Yup. It returns an HTMLCollection. If you add the following line to your JS, you can still use the forEach method of arrays on them, which makes them quite a bit nicer to use. HTMLCollection.prototype.forEach = Array.prototype.forEach;
  • Admin
    Admin almost 8 years
    @enhzflep modifying the prototypes of native objects is a horrible idea. Why not just use [].slice.call(document.getElementsByClassName('foobar')).for‌​Each()? Better yet, use document.querySelector(), which will actually do what the OP wants
  • Admin
    Admin almost 8 years
    This is helpful. However, the goal of my code is to stop displaying images one and two, while allowing image 3 to remain displayed and move into their place.
  • zer00ne
    zer00ne almost 8 years
    I don't recall that in the question, but I'll update my answer to comply...
  • Admin
    Admin almost 8 years
    You are right, I will go back and include that, thanks for the catch and the help!.
  • zer00ne
    zer00ne almost 8 years
    @JackElwell ok, done.
  • enhzflep
    enhzflep almost 8 years
    @TinyGiant - because I'm yet to have someone extol to me the virtues of the more verbose approach over the one I've suggested. A quick read after seeing your comment indicates the problem to lie with the possibility of things breaking in the future. This seems little, if any, different to adding custom attributes to HTML elements, which then go on to become standardised. autosuggest and lang both spring (perhaps erroneously) to mind. This is why it's considered a horrible idea?
  • Admin
    Admin almost 8 years
    @enhzflep Many problems can arise from extending native prototypes. This has been discussed to death countless times. There is plenty of information out there. If you refuse to acknowledge that information and insist on breaking things, that is your prerogative. If there is code other than your code on a page, and that code expects the native object to be a certain way, your code will interfere.
  • enhzflep
    enhzflep almost 8 years
    @TinyGiant - thank-you, I really do appreciate it. I've no recollection of hearing recommendations against it before your comment. Since I always get the whole page to myself, I hadn't even considered the "doesn't play nicely with others" part of the problem. I'm not sure if you're being snarky by implying that I've heard the info and ignored it, or if I've misinterpreted your words. In any case, it's news to me and I'm glad to have it. Fortunately, I've not received an angry phone-call because something has broken. Thanks for your assistance in avoiding them. That's today's biggest lesson. :)