javascripthtmlgetelementsbyclassname

How can I use getElementsbyClassName?


How can I use getElementsByClassName? I have many cards like this:

<div class="user-card Info-btn" id="Info-btn" style="display: flex; width: 400px;">
  <div class="left-card">
    <img src="" onError="this.onerror=null;this.src='{{ asset('img/not-found.jpg') }}';" style="display: block; margin-left: auto; margin-right: auto;" alt="">
  </div>
  <div class="right-card">
    <div class="right-top">
      <div style="padding-top: 15px;">
        <h1 class="user-name"></h1>
        <h1 style="color: #B4B4B4; font-size: 10px;"></h1>
      </div>
    </div>
    <div class="right-bottom">
      <h1>Admin</h1>
    </div>
  </div>
</div>

What I want is that when you click a card, a modal will display.

My JS looks like this:

var infomodal = document.getElementById("info-modal");
      
// Get the button that opens the modal
var infobtn = document.getElementsByClassName("Info-btn")[0];

// Get the <span> element that closes the modal
var infospan = document.getElementsByClassName("infoclose")[0];


// When the user clicks the button, open the modal 
infobtn.addEventListener("click", function(){
  infomodal.style.display = "block";
})

// When the user clicks on <span> (x), close the modal
infospan.addEventListener("click", function(){
  infomodal.style.display = "none";
})

// When the user clicks anywhere outside of the modal, close it
window.addEventListener("click", function(event){
  if (event.target == infomodal) {
    infomodal.style.display = "none";
  }
})

It works, but only the first card is able to display its modal and not the other cards.


Solution

  • getElementsByClassName returns a HTMLCollection (an array-like structure). Since you extract the first element of it (via [0]) and add an event listener only to the first element, it is obvious that only the first card is able to display it's modal.

    What you want instead is to add an event listener to each infospan element:

          var infomodal = document.getElementById("info-modal");
          
          // Get the button that opens the modal
          var infobtn = document.getElementsByClassName("Info-btn"); // <-- removed [0]
          
          // Get the <span> element that closes the modal
          var infospan = document.getElementsByClassName("infoclose"); // <-- same here
          
    
          // When the user clicks a button, open the modal 
          /*infobtn.addEventListener("click", function(){
            infomodal.style.display = "block";
          })*/
          Array.from(infobtn).forEach(btn => {
            btn.addEventListener('click', () => {
              infomodal.style.display = 'block';
            });
          });
          
          // When the user clicks on <span> (x), close the modal
          /*infospan.addEventListener("click", function(){
            infomodal.style.display = "none";
          })*/
          Array.from(infospan).forEach(span => {
            span.addEventListener('click', () => {
              infomodal.style.display = 'none';
            });
          });
          
          // When the user clicks anywhere outside of the modal, close it
          window.addEventListener("click", function(event){
            if (event.target == infomodal) {
              infomodal.style.display = "none";
            }
          })

    EDIT

    If you know that the number and ordering of the infospan elements equals the number and ordering of the infobtn elements, you can remove one of the .forEach iterations:

          var infomodal = document.getElementById("info-modal");
          
          // Get the button that opens the modal
          var infobtn = document.getElementsByClassName("Info-btn"); // <-- removed [0]
          
          // Get the <span> element that closes the modal
          var infospan = document.getElementsByClassName("infoclose"); // <-- same here
          
    
          // When the user clicks a button, open the modal 
          /*infobtn.addEventListener("click", function(){
            infomodal.style.display = "block";
          })*/
          Array.from(infobtn).forEach((btn, index) => {
            var span = infospan[index]; // <-- get the corresponding span
    
            btn.addEventListener('click', () => {
              infomodal.style.display = 'block';
            });
            span.addEventListener('click', () => {
              infomodal.style.display = 'none';
            });
          });
          
          
          // When the user clicks anywhere outside of the modal, close it
          window.addEventListener("click", function(event){
            if (event.target == infomodal) {
              infomodal.style.display = "none";
            }
          })