0

Here is a a demo application code to show images in a carousel. It works well with static images. But I want to add images to the carousel dynamically on a button click.

I added images on a button click, and it adds it in the container, which I can see if I debug the page using the browser's Developer Tools. But the image is not shown in the carousel.

Reference CodePen link

document.addEventListener("DOMContentLoaded", function() {
  let carousel = document.querySelector(".carousel");
  let items = carousel.querySelectorAll(".item");

  // Function to show a specific item
  function showItem(index) {
    items.forEach((item, idx) => {
      item.classList.remove("active");
      if (idx === index) {
        item.classList.add("active");
      }
    });
  }

  // Event listeners for buttons
  document.querySelector(".prev").addEventListener("click", () => {
    let index = [...items].findIndex((item) =>
      item.classList.contains("active")
    );
    showItem((index - 1 + items.length) % items.length);
  });

  document.querySelector(".next").addEventListener("click", () => {
    let index = [...items].findIndex((item) =>
      item.classList.contains("active")
    );
    showItem((index + 1) % items.length);
  });
});

//I tried the following function:
function buttonClicked() {
  const carouselContainer = document.querySelector('.carousel');

  // Create the carousel item
  const carouselItemContainer = document.createElement('div');
  carouselItemContainer.classList.add('item');

  // Create image element
  const imageElement = document.createElement('img');
  imageElement.src = "image URL";
  imageElement.alt = "test image";
  imageElement.classList.add("active");

  // Add a title below the image
  const imageTitle = document.createElement('p');
  imageTitle.textContent = "title of test image";
  imageTitle.classList.add('caption');

  carouselItemContainer.appendChild(imageElement);
  carouselItemContainer.appendChild(imageTitle);
  carouselContainer.appendChild(carouselItemContainer);
}
body {
  min-height: 100dvh;
  display: flex;
  align-items: center;
  font-family: "Satoshi", sans-serif;
  font-size: var(--lx-text-01);
  font-weight: 500;
  color: #ffffe6;
  background-color: #10100e;
}

.carousel-container {
  width: 80%;
  margin: auto;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--lx-gap);

  .carousel {
    aspect-ratio: 16/9;
    width: 100%;
    position: relative;
    overflow: hidden;

    .item {
      opacity: 0;
      width: 100%;
      height: 100%;
      display: none;
      transition: opacity 0.5s ease-in-out;

      img {
        width: 100%;
        height: 100%;
        object-fit: cover;
        object-position: center;
      }

      .caption {
        width: 100%;
        padding: var(--lx-space-01);
        position: absolute;
        bottom: 0;
        text-transform: uppercase;
        text-align: center;
        font-size: 12px;
        background-color: rgba(0, 0, 0, 0.5);
      }

      &.active {
        opacity: 1;
        display: block;
      }
    }
  }

  .btn {
    padding: 1em 2em;
    position: absolute;
    transform: translateY(-50%);
    top: 50%;
    outline: none;
    border: none;
    cursor: pointer;
    text-transform: uppercase;
    font-size: 12px;
    font-weight: 900;
    color: #10100e;
    background-color: #ffffe6;
    transition: transform 0.2s ease-in-out;

    &:active,
    &:focus {
      transform: translateY(-50%) scale(0.9);
    }

    &:hover {
      transform: translateY(-50%) scale(0.96);
    }
  }

  .prev {
    left: -5%;
  }

  .next {
    right: -5%;
  }
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <title>Image Slider</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" />

  <link rel="stylesheet" href="style - copy.css" />
  <script src="script - copy.js"></script>
</head>

<body>
  <main class="carousel-container">
  <div class="carousel">
    <div class="item active">
      <img src="https://images.unsplash.com/photo-1457732815361-daa98277e9c8?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80" alt="Image 1" />
      <p class="caption">Caption for Image 1</p>
    </div>
    <div class="item">
      <img src="https://images.unsplash.com/photo-1500206329404-5057e0aefa48?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=crop&amp;w=1355&amp;q=80" alt="Image 2" />
      <p class="caption">Caption for Image 2</p>
    </div>
    <div class="item">
      <img src="https://images.unsplash.com/photo-1502239608882-93b729c6af43?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=crop&amp;w=1350&amp;q=80" alt="Image 3" />
      <p class="caption">Caption for Image 3</p>
    </div>
  </div>
  <button class="btn prev">Prev</button>
  <button class="btn next">Next</button>
  <div class="dots"></div>
</main>
</body>

</html>

It adds the image to the carousel container but the image is not displayed in the carousel.

2 Answers 2

2

Because the "next" and "prev" buttons in your code find the next image from the items array (rather than reading direct from the carousel container elemente each time), you need to ensure you re-initialise items after you've added the new image, by reading the list of elements from the carousel container again.

Once you add that step, your code works fine - demo:

document.addEventListener("DOMContentLoaded", function() {
  let carousel = document.querySelector(".carousel");
  let items = carousel.querySelectorAll(".item");

  // Function to show a specific item
  function showItem(index) {
    items.forEach((item, idx) => {
      item.classList.remove("active");
      if (idx === index) {
        item.classList.add("active");
      }
    });
  }

  // Event listeners for buttons
  document.querySelector(".prev").addEventListener("click", () => {
    let index = [...items].findIndex((item) =>
      item.classList.contains("active")
    );
    showItem((index - 1 + items.length) % items.length);
  });

  document.querySelector(".next").addEventListener("click", () => {
    let index = [...items].findIndex((item) =>
      item.classList.contains("active")
    );
    showItem((index + 1) % items.length);
  });

  document.querySelector("#addImage").addEventListener("click", function(e) {
    const carouselContainer = document.querySelector('.carousel');

    // Create the carousel item
    const carouselItemContainer = document.createElement('div');
    carouselItemContainer.classList.add('item');

    // Create image element
    const imageElement = document.createElement('img');
    imageElement.src = "https://i.imgur.com/db4KgSp.png";
    imageElement.alt = "test image";
    imageElement.classList.add("active");

    // Add a title below the image
    const imageTitle = document.createElement('p');
    imageTitle.textContent = "title of test image";
    imageTitle.classList.add('caption');

    carouselItemContainer.appendChild(imageElement);
    carouselItemContainer.appendChild(imageTitle);
    carouselContainer.appendChild(carouselItemContainer);
    items = carousel.querySelectorAll(".item");
  });

});
body {
  min-height: 100dvh;
  display: flex;
  align-items: center;
  font-family: "Satoshi", sans-serif;
  font-size: var(--lx-text-01);
  font-weight: 500;
  color: #ffffe6;
  background-color: #10100e;
}

.carousel-container {
  width: 80%;
  margin: auto;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--lx-gap);

  .carousel {
    aspect-ratio: 16/9;
    width: 100%;
    position: relative;
    overflow: hidden;

    .item {
      opacity: 0;
      width: 100%;
      height: 100%;
      display: none;
      transition: opacity 0.5s ease-in-out;

      img {
        width: 100%;
        height: 100%;
        object-fit: cover;
        object-position: center;
      }

      .caption {
        width: 100%;
        padding: var(--lx-space-01);
        position: absolute;
        bottom: 0;
        text-transform: uppercase;
        text-align: center;
        font-size: 12px;
        background-color: rgba(0, 0, 0, 0.5);
      }

      &.active {
        opacity: 1;
        display: block;
      }
    }
  }

  .btn {
    padding: 1em 2em;
    position: absolute;
    transform: translateY(-50%);
    top: 50%;
    outline: none;
    border: none;
    cursor: pointer;
    text-transform: uppercase;
    font-size: 12px;
    font-weight: 900;
    color: #10100e;
    background-color: #ffffe6;
    transition: transform 0.2s ease-in-out;

    &:active,
    &:focus {
      transform: translateY(-50%) scale(0.9);
    }

    &:hover {
      transform: translateY(-50%) scale(0.96);
    }
  }

  .prev {
    left: -5%;
  }

  .next {
    right: -5%;
  }
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <title>Image Slider</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" />

  <link rel="stylesheet" href="style - copy.css" />
  <script src="script - copy.js"></script>
</head>

<body>
  <div><button type="button" id="addImage">Add Image</button></div>
  <main class="carousel-container">
    <div class="carousel">
      <div class="item active">
        <img src="https://images.unsplash.com/photo-1457732815361-daa98277e9c8?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80" alt="Image 1" />
        <p class="caption">Caption for Image 1</p>
      </div>
      <div class="item">
        <img src="https://images.unsplash.com/photo-1500206329404-5057e0aefa48?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=crop&amp;w=1355&amp;q=80" alt="Image 2" />
        <p class="caption">Caption for Image 2</p>
      </div>
      <div class="item">
        <img src="https://images.unsplash.com/photo-1502239608882-93b729c6af43?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=crop&amp;w=1350&amp;q=80" alt="Image 3" />
        <p class="caption">Caption for Image 3</p>
      </div>
    </div>
    <button class="btn prev">Prev</button>
    <button class="btn next">Next</button>
    <div class="dots"></div>
  </main>
</body>

</html>

Sign up to request clarification or add additional context in comments.

7 Comments

This is amazing! Is it possible to display the newly added image when we click add image button? Thank you !!
Yes I would expect it's possible. Have you thought about how you might do it?
I'm not that familiar with the technology, but I think ShowItem() function can be used in the button click event. The index could be equal to the length of container. I will give it a try and update soon. Thank you!
I added a function: function showLast() { const lastIndex = items.length - 1; showItem(lastIndex); // Show the last item } And called it at the end of the button click event handler : document.querySelector("#addImage").addEventListener("click", function(e) It works!! Thank you so much for the help @ADyson !
@Preetiv No problem. Have you also considered chrwahl's recent answer? It solves the problem in perhaps a slightly more elegant way. Remember to mark the answer which was most helpful as "accepted" (by clicking the tick next to it, so it turns green).
|
1

Instead of relying on indexes and (global'ish) variables you can selecte the next/previous images based on the current active image. And when adding a new image you can just use that reference to display the image.

document.addEventListener("DOMContentLoaded", function() {
  // Event listeners for buttons
  document.querySelector(".carousel-container").addEventListener("click", carouselBtnHandler);
  document.querySelector("#addImage").addEventListener("click", addImageHandler);
});

// Function to show a specific item
function showItem(elm) {
  elm.closest('.carousel').querySelectorAll(".item")
    .forEach(item => item.classList.remove("active"));
  elm.classList.add('active');
}

// Function for handling click events on buttons on the carousel
function carouselBtnHandler(e) {
  let carousel = e.target.closest('.carousel-container').querySelector('.carousel');
  let activeElm = carousel.querySelector('.active');
  switch(e.target.name){
    case 'prev':
     showItem(activeElm.previousElementSibling ?? carousel.lastElementChild);
      break;
    case 'next':
      showItem(activeElm.nextElementSibling ?? carousel.firstElementChild);
      break;
  }
}

// Function for adding image
function addImageHandler(e) {
  const carouselContainer = document.querySelector('.carousel');

  // Create the carousel item
  const carouselItemContainer = document.createElement('div');
  carouselItemContainer.classList.add('item');

  // Create image element
  const imageElement = document.createElement('img');
  
  imageElement.alt = "test image";
  imageElement.classList.add("active");

  // Add a title below the image
  const imageTitle = document.createElement('p');
  imageTitle.textContent = "title of test image";
  imageTitle.classList.add('caption');

  carouselItemContainer.appendChild(imageElement);
  carouselItemContainer.appendChild(imageTitle);
  carouselContainer.appendChild(carouselItemContainer);
  
  // Show the new image
  imageElement.addEventListener('load', e => {
    showItem(e.target.closest('.item'));
  });
  imageElement.src = "https://i.imgur.com/db4KgSp.png";

}
body {
  min-height: 100dvh;
  display: flex;
  align-items: center;
  font-family: "Satoshi", sans-serif;
  font-size: var(--lx-text-01);
  font-weight: 500;
  color: #ffffe6;
  background-color: #10100e;
}

.carousel-container {
  width: 80%;
  margin: auto;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--lx-gap);

  .carousel {
    aspect-ratio: 16/9;
    width: 100%;
    position: relative;
    overflow: hidden;

    .item {
      opacity: 0;
      width: 100%;
      height: 100%;
      display: none;
      transition: opacity 0.5s ease-in-out;

      img {
        width: 100%;
        height: 100%;
        object-fit: cover;
        object-position: center;
      }

      .caption {
        width: 100%;
        padding: var(--lx-space-01);
        position: absolute;
        bottom: 0;
        text-transform: uppercase;
        text-align: center;
        font-size: 12px;
        background-color: rgba(0, 0, 0, 0.5);
      }

      &.active {
        opacity: 1;
        display: block;
      }
    }
  }

  .btn {
    padding: 1em 2em;
    position: absolute;
    transform: translateY(-50%);
    top: 50%;
    outline: none;
    border: none;
    cursor: pointer;
    text-transform: uppercase;
    font-size: 12px;
    font-weight: 900;
    color: #10100e;
    background-color: #ffffe6;
    transition: transform 0.2s ease-in-out;

    &:active,
    &:focus {
      transform: translateY(-50%) scale(0.9);
    }

    &:hover {
      transform: translateY(-50%) scale(0.96);
    }
  }

  .prev {
    left: -5%;
  }

  .next {
    right: -5%;
  }
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <title>Image Slider</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" />

  <link rel="stylesheet" href="style - copy.css" />
  <script src="script - copy.js"></script>
</head>

<body>
  <div><button type="button" id="addImage">Add Image</button></div>
  <main class="carousel-container">
    <div class="carousel">
      <div class="item active">
        <img src="https://images.unsplash.com/photo-1457732815361-daa98277e9c8?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80" alt="Image 1" />
        <p class="caption">Caption for Image 1</p>
      </div>
      <div class="item">
        <img src="https://images.unsplash.com/photo-1500206329404-5057e0aefa48?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=crop&amp;w=1355&amp;q=80" alt="Image 2" />
        <p class="caption">Caption for Image 2</p>
      </div>
      <div class="item">
        <img src="https://images.unsplash.com/photo-1502239608882-93b729c6af43?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=crop&amp;w=1350&amp;q=80" alt="Image 3" />
        <p class="caption">Caption for Image 3</p>
      </div>
    </div>
    <button name="prev" class="btn prev">Prev</button>
    <button name="next" class="btn next">Next</button>
    <div class="dots"></div>
  </main>
</body>

</html>

1 Comment

As ADyson has mentioned, this must be an elegant solution, so I will give it a try. Thanks for this solution!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.