skip to Main Content

I have a simple jquery block where I’m navigating through text slides with buttons. This is working and I don’t want to change how it’s operating but I would like to make it automatic as well. In other words, if nobody clicks the buttons the process would automatically proceed to the next every 4 or 5 seconds.

One thought I had was to simulate a next button click with jquery, but I’m confused on how to actually target the next button due to the way I’ve declared my buttons. I have a setInterval for 4 seconds that triggers the data-carousel-button but how do I actually target the ‘next’ version of that button?

const buttons = document.querySelectorAll("[data-carousel-button]")

buttons.forEach(button => {
  button.addEventListener("click", () => {
    const offset = button.dataset.carouselButton === "next" ? 1 : -1
    const slides = button
      .closest("[data-carousel]")
      .querySelector("[data-slides]")

    const activeSlide = slides.querySelector("[data-active]")
    let newIndex = [...slides.children].indexOf(activeSlide) + offset
    if (newIndex < 0) newIndex = slides.children.length - 1
    if (newIndex >= slides.children.length) newIndex = 0

    slides.children[newIndex].dataset.active = true
    delete activeSlide.dataset.active
  })
})

setInterval(function() {
  $("data-carousel-button").trigger("click");
}, 4000);
.slideshow_overlay {
  padding: 30px;
  position: absolute;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 30px;
  bottom: 5;
  bottom: 0;
  height: 15vh;
  background: rgba(0, 0, 0, 0.3);
  width: 100vw;
  margin-left: 0px;
}

.slideshow_overlay-btnGroup {
  display: flex;
}

.hero_slideshow {
  width: 100vw;
  height: calc(100vh - 105px);
  min-height: 400px !important;
  margin-top: 105px;
  position: relative;
}

.hero_slideshow ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.hero_carousel-button {
  backgorund: none;
  border: none;
  z-index: 2;
  font-size: 4rem;
  top: 50%;
  transform: translateY(-50%);
  color: rgba(255, 255, 255, .5);
  cursor: pointer;
  border-radius: .25rem;
  padding: 0 .5rem;
  background-color: rgba(0, 0, 0, .1);
}

.hero_carousel-button:hover,
.hero_carousel-button:focus {
  color: white;
  background-color: rgba(0, 0, 0, .2);
}

.slide_hero {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: 200ms opacity ease-in-out;
  transition-delay: 200ms;
}

.slide_hero>.slide_hero__img {
  display: block;
  width: 100%;
  height: calc(100vh - 105px);
  min-height: 400px !important;
  object-fit: cover;
  object-position: center;
}

.slide_hero[data-active] {
  opacity: 1;
  z-index: 1;
  transition-delay: 0ms;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section aria-label="Hero Slideshow">
  <div class="hero_slideshow" data-carousel>
    <button class="hero_carousel-button prev" data-carousel-button="prev">Prev</button>
    <button class="hero_carousel-button next" data-carousel-button="next">next</button>
    <ul data-slides>
      <li class="slide_hero" data-active>
        Test 1
      </li>
      <li class="slide_hero">
        Test 2
      </li>
    </ul>
  </div>
</section>

3

Answers


  1. You are REALLY overthinking this. The data attributes are not necessary here

    I had to fix the CSS to just use .active

    const $slides = $(".slides li");
    $(".hero_carousel-button").on("click", function() {
      const next = $(this).is(".next");
      const idx = $slides.filter(".active").index()
      let $activeSlide = $slides.eq(idx + (next ? 1 : -1))
      if ($activeSlide.length === 0) {
        $activeSlide = $slides[next ? "first" : "last"]() // first or last
      }
      $slides.removeClass("active");
      $activeSlide.addClass("active");
    })
    
    setInterval(function() {
      $(".next").trigger("click");
    }, 4000);
    .slideshow_overlay {
      padding: 30px;
      position: absolute;
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 30px;
      bottom: 5;
      bottom: 0;
      height: 15vh;
      background: rgba(0, 0, 0, 0.3);
      width: 100vw;
      margin-left: 0px;
    }
    
    .slideshow_overlay-btnGroup {
      display: flex;
    }
    
    .hero_slideshow {
      width: 100vw;
      height: calc(100vh - 105px);
      min-height: 400px !important;
      margin-top: 105px;
      position: relative;
    }
    
    .hero_slideshow ul {
      margin: 0;
      padding: 0;
      list-style: none;
    }
    
    .hero_carousel-button {
      background: none;
      border: none;
      z-index: 2;
      font-size: 4rem;
      top: 50%;
      transform: translateY(-50%);
      color: rgba(255, 255, 255, .5);
      cursor: pointer;
      border-radius: .25rem;
      padding: 0 .5rem;
      background-color: rgba(0, 0, 0, .1);
    }
    
    .hero_carousel-button:hover,
    .hero_carousel-button:focus {
      color: white;
      background-color: rgba(0, 0, 0, .2);
    }
    
    .slide_hero {
      position: absolute;
      inset: 0;
      opacity: 0;
      transition: 200ms opacity ease-in-out;
      transition-delay: 200ms;
    }
    
    .slide_hero>.slide_hero__img {
      display: block;
      width: 100%;
      height: calc(100vh - 105px);
      min-height: 400px !important;
      object-fit: cover;
      object-position: center;
    }
    
    .slide_hero.active {
      opacity: 1;
      z-index: 1;
      transition-delay: 0ms;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <section aria-label="Hero Slideshow">
      <div class="hero_slideshow">
        <button class="hero_carousel-button prev">Prev</button>
        <button class="hero_carousel-button next">next</button>
        <ul class="slides">
          <li class="slide_hero active">
            Test 1
          </li>
          <li class="slide_hero">
            Test 2
          </li>
          <li class="slide_hero">
            Test 3
          </li>
          <li class="slide_hero">
            Test 4
          </li>
        </ul>
      </div>
    </section>
    Login or Signup to reply.
  2. You are not supplying the correct selector in your setInterval callback so you should change this

    setInterval(function() {
      $("data-carousel-button").trigger("click");
    }, 4000);
    

    into this

    setInterval(function() {
      // this selector, which is called attribute selector, will target the buttons having the "data-carousel-button" set to "next"
      $("[data-carousel-button=next]").trigger("click");
    }, 4000);
    

    And here’s a live demo of your code’s corrected version:

    const buttons = document.querySelectorAll("[data-carousel-button]")
    
    buttons.forEach(button => {
      button.addEventListener("click", () => {
        const offset = button.dataset.carouselButton === "next" ? 1 : -1
        const slides = button
          .closest("[data-carousel]")
          .querySelector("[data-slides]")
    
        const activeSlide = slides.querySelector("[data-active]")
        let newIndex = [...slides.children].indexOf(activeSlide) + offset
        if (newIndex < 0) newIndex = slides.children.length - 1
        if (newIndex >= slides.children.length) newIndex = 0
    
        slides.children[newIndex].dataset.active = true
        delete activeSlide.dataset.active
      })
    })
    
    setInterval(function() {
      $("[data-carousel-button=next]").trigger("click");
    }, 4000);
    .slideshow_overlay {
      padding: 30px;
      position: absolute;
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 30px;
      bottom: 5;
      bottom: 0;
      height: 15vh;
      background: rgba(0, 0, 0, 0.3);
      width: 100vw;
      margin-left: 0px;
    }
    
    .slideshow_overlay-btnGroup {
      display: flex;
    }
    
    .hero_slideshow {
      width: 100vw;
      height: calc(100vh - 105px);
      min-height: 400px !important;
      margin-top: 105px;
      position: relative;
    }
    
    .hero_slideshow ul {
      margin: 0;
      padding: 0;
      list-style: none;
    }
    
    .hero_carousel-button {
      backgorund: none;
      border: none;
      z-index: 2;
      font-size: 4rem;
      top: 50%;
      transform: translateY(-50%);
      color: rgba(255, 255, 255, .5);
      cursor: pointer;
      border-radius: .25rem;
      padding: 0 .5rem;
      background-color: rgba(0, 0, 0, .1);
    }
    
    .hero_carousel-button:hover,
    .hero_carousel-button:focus {
      color: white;
      background-color: rgba(0, 0, 0, .2);
    }
    
    .slide_hero {
      position: absolute;
      inset: 0;
      opacity: 0;
      transition: 200ms opacity ease-in-out;
      transition-delay: 200ms;
    }
    
    .slide_hero>.slide_hero__img {
      display: block;
      width: 100%;
      height: calc(100vh - 105px);
      min-height: 400px !important;
      object-fit: cover;
      object-position: center;
    }
    
    .slide_hero[data-active] {
      opacity: 1;
      z-index: 1;
      transition-delay: 0ms;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <section aria-label="Hero Slideshow">
      <div class="hero_slideshow" data-carousel>
        <button class="hero_carousel-button prev" data-carousel-button="prev">Prev</button>
        <button class="hero_carousel-button next" data-carousel-button="next">next</button>
        <ul data-slides>
          <li class="slide_hero" data-active>
            Test 1
          </li>
          <li class="slide_hero">
            Test 2
          </li>
        </ul>
      </div>
    </section>

    Learn more about Attribute Selectors on MDN.

    Login or Signup to reply.
  3. Since your carousal is in loop (like if it a last slider then it go back to first) you can target the next button alone.
    And also you need to use "clearInterval" function along with this In-order to avoid the slider override behaviour (if you are trying to interfere when the auto carousel is also trying to run the next button) that you can prevent by clearing the interval on every button click made by you.
    This code made your carousel flexible.

    See working example here: https://jsbin.com/diwomakime/edit?html,css,js,output

    const buttons = document.querySelectorAll("[data-carousel-button]");
    
    /*** new changes ***/
    var myCarouselInterval = setInterval(nextSlide, 4000);
    
    buttons.forEach(button => {
      button.addEventListener("click", () => {
    
      /*** new changes ***/
      clearSlideInterval();
      const offset = button.dataset.carouselButton === "next" ? 1 : -1
      const slides = button
        .closest("[data-carousel]")
        .querySelector("[data-slides]")
    
      const activeSlide = slides.querySelector("[data-active]")
      let newIndex = [...slides.children].indexOf(activeSlide) + offset
      if (newIndex < 0) newIndex = slides.children.length - 1
      if (newIndex >= slides.children.length) newIndex = 0
    
      slides.children[newIndex].dataset.active = true
      delete activeSlide.dataset.active
     })
    })
    
    function nextSlide() {
      /*** new changes ***/
      $(".next[data-carousel-button]").trigger("click");
    }
    
    /*** new changes ***/
    function clearSlideInterval() {
      clearInterval(myCarouselInterval);
      myCarouselInterval = setInterval(nextSlide, 4000);
    } 
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search