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