skip to Main Content

I’m trying to build a card navigation feature in JavaScript where clicking on a card displays its content in a hiddenCard element, and I can navigate between cards using left and right arrow buttons.

Selecting Cards and the Hidden Card:

var cards=document.querySelectorAll(".card");

var hiddenCard=document.querySelector(".card_hidden")

var currntIndex=0;

Adding Click Event to Each Card:

for (var i = 0; i < cards.length; i++) {
  cards[i].addEventListener("click", function () {
    currntIndex = Array.from(cards).indexOf(this);

    var image = this.querySelector("img");
    var title = this.querySelector(".title p");

    hiddenCard.innerHTML = `
      <p>${title.textContent}</p>
      <img src=${image.src}> 
      <i class="fa-solid fa-arrow-left pre"></i>
      <i class="fa-solid fa-arrow-right next"></i>
    `;

    hiddenCard.style.display = "block";

    console.log(hiddenCard);

    arrows();
  });
}

Adding Navigation with Arrows:

function arrows() {
  document.querySelector(".pre").addEventListener("click", function () {
    if (currntIndex > 0) {
      currntIndex--;
      showIndex(currntIndex);
    }
  });

  document.querySelector(".next").addEventListener("click", function () {
    if (currntIndex < cards.length - 1) {
      currntIndex++;
      showIndex(currntIndex);
    }
  });
}

Updating the Hidden Card:

function showIndex(currntIndex) {
  var imagIndex = cards[currntIndex].querySelector("img");
  var titleIndex = cards[currntIndex].querySelector(".title p");

  hiddenCard.innerHTML = `
    <p>${titleIndex.textContent}</p>
    <img src=${imagIndex.src}> 
    <i class="fa-solid fa-arrow-left pre"></i>
    <i class="fa-solid fa-arrow-right next"></i>
  `;
}

The hiddenCard displays correctly when I click on a card. However, when I use the arrow buttons, the hiddenCard content doesn’t update, or the navigation doesn’t work as expected.

2

Answers


  1. You are calling arrows inside each of your event, so if you have 100 pictures, then you’ll assign 100 pre and next click event handlers, so clicking on pre or next will not only execute once, but many times. I have hidden cards for this example, feel free to change it however you please.

    var cards=document.querySelectorAll(".card");
    
    var hiddenCard=document.querySelector(".card_hidden")
    
    var currntIndex=0;
    
    for (var i = 0; i < cards.length; i++) {
      cards[i].addEventListener("click", function () {
        currntIndex = Array.from(cards).indexOf(this);
    
        var image = this.querySelector("img");
        var title = this.querySelector(".title p");
    
        hiddenCard.innerHTML = `
          <p>${title.textContent}</p>
          <img src=${image.src}> 
          <i class="fa-solid fa-arrow-left pre"></i>
          <i class="fa-solid fa-arrow-right next"></i>
        `;
    
        hiddenCard.style.display = "block";
    
        console.log(hiddenCard);
        
      });
    }
    
    function arrows() {
      document.querySelector(".pre").addEventListener("click", function () {
        if (currntIndex > 0) {
          currntIndex--;
          showIndex(currntIndex);
        }
      });
    
      document.querySelector(".next").addEventListener("click", function () {
        if (currntIndex < cards.length - 1) {
          currntIndex++;
          showIndex(currntIndex);
        }
      });
    }
    
    arrows();
    
    function showIndex(currntIndex) {
      var imagIndex = cards[currntIndex].querySelector("img");
      var titleIndex = cards[currntIndex].querySelector(".title p");
    
      hiddenCard.innerHTML = `
        <p>${titleIndex.textContent}</p>
        <img src=${imagIndex.src}> 
        <i class="fa-solid fa-arrow-left pre"></i>
        <i class="fa-solid fa-arrow-right next"></i>
      `;
    }
    
    showIndex(0);
    .card {
        display: none;
    }
    
    .container {
        display: block ruby;
    }
    
    img {
        width: 100px;
        height: 100px;
    }
    <div class="card">
        <div class="title">
            <p>a</p>
        </div>
        <img src="https://next-images.123rf.com/index/_next/image/?url=https://assets-cdn.123rf.com/index/static/assets/top-section-bg.jpeg&w=3840&q=75">
    </div>
    <div class="card">
        <div class="title">
            <p>b</p>
        </div>
        <img src="https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885_1280.jpg">
    </div>
    <div class="card">
        <div class="title">
            <p>c</p>
        </div>
        <img src="https://letsenhance.io/static/8f5e523ee6b2479e26ecc91b9c25261e/1015f/MainAfter.jpg">
    </div>
    <div class="card">
        <div class="title">
            <p>c</p>
        </div>
        <img src="https://images.pexels.com/photos/674010/pexels-photo-674010.jpeg?cs=srgb&dl=pexels-anjana-c-169994-674010.jpg&fm=jpg">
    </div>
    <div class="container">
    <div class="pre"><</div>
    <div class="card_hidden">
    </div>
    <div class="next">></div>
    </div>
    Login or Signup to reply.
  2. Recommend that you implement a single event handler which takes advantage of event bubbling. Create the event handler on the parent element, and inspect the target (which is passed to the handler in the Event object) to determine which arrow or card was clicked.

    const cards = Array.from(document.querySelectorAll('.card'))
    let currentIndex = 0
    
    const selectSlide = index => {
      document.querySelector('.card-hidden').innerHTML = cards[index].innerHTML
    }
    
    selectSlide(currentIndex)
    
    document.querySelector('.d1').addEventListener('click', evt => {
      if (evt.target.closest('.nav')) {
        if (evt.target.closest('.nav').classList.contains('previous'))
          currentIndex = currentIndex == 0 ? 0 : currentIndex - 1
        else 
          currentIndex = currentIndex == cards.length - 1 ? cards.length - 1 : currentIndex + 1
        selectSlide(currentIndex)
      }
      else if (evt.target.closest('.card')) {
        currentIndex = cards.indexOf(evt.target.closest('.card'))
        selectSlide(currentIndex)
      }
    })
    .d1 {
      display: flex;
      gap: 1em;
      align-items: center;
      margin-bottom: 1em;
    }
    
    .card, .nav, img {
      border-radius: 5px;
    }
    
    .nav {
      padding: 5px;
      font-weight: bold;
    }
    
    .card, .card-hidden {
      width: 100px;
    }
    
    .card:hover, .nav:hover {
      color: white;
      background: orange;
      box-shadow: 0 0 10px rgb(0 0 0 / 0.3);
    }
    
    
    h4 {
      margin: 0 0 5px;
      text-align: center;
    }
    
    img {
      width: 100%;
      aspect-ratio: 1;
      display: block;
    }
    <div class="d1">
      <div class="nav previous"> < </div>
      <div class="card">
        <h4>a</h4>
        <img src="https://next-images.123rf.com/index/_next/image/?url=https://assets-cdn.123rf.com/index/static/assets/top-section-bg.jpeg&w=3840&q=75">
      </div>
      <div class="card">
        <h4>b</h4>
        <img src="https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885_1280.jpg">
      </div>
      <div class="card">
        <h4>c</h4>
        <img src="https://letsenhance.io/static/8f5e523ee6b2479e26ecc91b9c25261e/1015f/MainAfter.jpg">
      </div>
      <div class="card">
        <h4>d</h4>
        <img src="https://images.pexels.com/photos/674010/pexels-photo-674010.jpeg?cs=srgb&dl=pexels-anjana-c-169994-674010.jpg&fm=jpg">
      </div>
      <div class="nav next"> > </div>
    </div>
    
    <div class="card-hidden"></div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search