Home > Software engineering >  targeting click of a specific button type with jquery
targeting click of a specific button type with jquery

Time:09-19

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  data-carousel>
    <button  data-carousel-button="prev">Prev</button>
    <button  data-carousel-button="next">next</button>
    <ul data-slides>
      <li  data-active>
        Test 1
      </li>
      <li >
        Test 2
      </li>
    </ul>
  </div>
</section>

CodePudding user response:

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  data-carousel>
    <button  data-carousel-button="prev">Prev</button>
    <button  data-carousel-button="next">next</button>
    <ul data-slides>
      <li  data-active>
        Test 1
      </li>
      <li >
        Test 2
      </li>
    </ul>
  </div>
</section>

Learn more about Attribute Selectors on MDN.

CodePudding user response:

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 >
    <button >Prev</button>
    <button >next</button>
    <ul >
      <li >
        Test 1
      </li>
      <li >
        Test 2
      </li>
      <li >
        Test 3
      </li>
      <li >
        Test 4
      </li>
    </ul>
  </div>
</section>

CodePudding user response:

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);
} 
  • Related