Reset slider JavaScript upon window resize (NOT jQuery) - javascript

I do not want a jQuery solution.
The problem: When my page is resized, the slides in the slider are positioned incorrectly.
I'm open to any solution, but my guess is I need to reset the JS for my heroSlider upon window resizing.
Here's the JSfiddle https://jsfiddle.net/3ou0ja4c/
// HERO SLIDER
const heroSlider = () => {
const carouselSlide = document.querySelector('.carousel-slide')
let carouselImages = document.querySelectorAll('.carousel-slide .slide-bg')
// Buttons
const prevBtn = document.querySelector('#prevBtn')
const nextBtn = document.querySelector('#nextBtn')
// Timer
let interval = setInterval( () => rotateSlide(), 5000)
// Counter
let counter = 1
let size = carouselImages[0].clientWidth
carouselSlide.style.transform = 'translateX(' + (-size * counter ) + 'px)'
const rotateSlide = () => {
if (counter >= carouselImages.length -1) return
carouselSlide.style.transition = "transform 0.4s ease-in-out"
counter++
carouselSlide.style.transform = 'translateX(' + (-size * counter ) + 'px)'
}
// Button Listeners
nextBtn.addEventListener('click',() => {
clearInterval(interval)
rotateSlide()
})
prevBtn.addEventListener('click', () => {
if (counter <= 0) return
carouselSlide.style.transition = "transform 0.4s ease-in-out"
counter--
carouselSlide.style.transform = 'translateX(' + (-size * counter ) + 'px)'
clearInterval(interval)
})
carouselSlide.addEventListener('transitionend', () => {
// If image is a clone, jump to original image with no animation
if (carouselImages[counter].id === 'lastClone'){
carouselSlide.style.transition = "none"
counter = carouselImages.length - 2
carouselSlide.style.transform = 'translateX(' + (-size * counter ) + 'px)'
}
if (carouselImages[counter].id === 'firstClone'){
carouselSlide.style.transition = "none"
counter = carouselImages.length - counter
carouselSlide.style.transform = 'translateX(' + (-size * counter ) + 'px)'
}
})
}
heroSlider()
It doesn't look great on the fiddle, but you can still see it breaks upon being resized. It works on all window sizes, so long as you refresh the page, but I DO NOT want the page to refresh upon all resizes.
You can see the real deal over at http://www.justinkwapich.com/JH/index.html
Any help is really appreciated, thank you!

In your heroSlider() function you can add an event listener to check if the window is resized and create a callback where you update the size variable and anything else that depends on this size:
let counter = 1
let size = carouselImages[0].clientWidth
window.addEventListener('resize', () => {
size = carouselImages[0].clientWidth
carouselSlide.style.transform = 'translateX(' + (-size * counter ) + 'px)'
// ...
// ...
})

Related

Slider's width isn't updating without refreshing the page

When the page resizes "sliderContainerWidth" sticks with the same width, but if i refresh the page on any width its works fine.. I've tried using resize event as u guys can see i couldn't fixed it. It's not updating without refreshing the page..
let counter = 0;
const back = document.querySelector("#back");
const next = document.querySelector("#next");
const sliderContainer = document.querySelector("#slider-container");
var sliderContainerWidth =
document.querySelector("#slider-container").clientWidth;
const slider = document.querySelector("#slider");
const max = document.querySelectorAll(".slide").length - 1;
window.addEventListener("resize", sliderFunc);
next.addEventListener("click", sliderFunc);
function sliderFunc() {
if (counter < max) {
counter++;
slider.style.left = "-" + sliderContainerWidth * counter + "px";
} else {
counter = 0;
slider.style.left = "-" + sliderContainerWidth * counter + "px";
}
}
window.addEventListener("resize", backEvent);
back.addEventListener("click", backEvent);
function backEvent() {
if (counter >= 1) {
counter--;
slider.style.left = "-" + sliderContainerWidth * counter + "px";
} else {
counter = max;
slider.style.left = "-" + sliderContainerWidth * counter + "px";
}
}
//mousevnt
let timer = setInterval(sliderFunc, 12000);
sliderContainer.addEventListener("mouseover", () => {
clearInterval(timer);
});
sliderContainer.addEventListener("mouseout", () => {
timer = setInterval(sliderFunc, 12000);
});
//mousevnt
If I'm understanding your issue correctly, you need to update the value inside of your event functions. It will not update if it's not getting set. The reason it only gets set when you refresh is because all the top-level javascript gets read when the page first loads.
function sliderFunc() {
if (counter < max) {
counter++;
slider.style.left = "-" + sliderContainerWidth * counter + "px";
} else {
counter = 0;
slider.style.left = "-" + sliderContainerWidth * counter + "px";
}
sliderContainerWidth = document.querySelector("#slider-container").clientWidth;
}

Images do not fit inside slider

I've created an image slider using HTML and JS.
One problem I've come across that I cant quite work myself around is how the image slider transmits multiple images for each slide when the dimensions of the image does not perfectly fit the box. I would like to change this code so that there is only one image displayed at a single time + the image is centered to the box.
Does anyone have any suggestions on to how I would edit this?
Please let me know if any additional information is needed.
const carouselSlide = document.querySelector('.carousel-slide');
const carouselImages = document.querySelectorAll('.carousel-slide img');
const prevBtn = document.querySelector('#prevBtn');
const nextBtn = document.querySelector('#nextBtn');
let counter = 1;
const size = carouselImages[0].clientWidth;
carouselSlide.style.transform = 'translateX(' + (-size * counter) + 'px)';
//Button Listeners
nextBtn.addEventListener('click', () => {
if (counter >= carouselImages.length - 1) {
return;
}
carouselSlide.style.tranisition = "transform 0.4s ease-in-out"
counter++;
carouselSlide.style.transform = 'translateX(' + (-size * counter) + 'px)';
});
prevBtn.addEventListener('click', () => {
if (counter <= 0) {
return;
}
carouselSlide.style.tranisition = "transform 0.4s ease-in-out"
counter--;
carouselSlide.style.transform = 'translateX(' + (-size * counter) + 'px)';
});
carouselSlide.addEventListener('transitonend', () => {
if (carouselImages[counter].id === 'lastclone') {
carouselSlide.style.transition = "none";
counter = carouselImage.length - 2;
carouselSlide.style.transform = 'translateX(' + (-size * counter) + 'px)';
}
if (carouselImages[counter].id === 'firstclone') {
carouselSlide.style.transition = "none";
counter = carouselImage.length - counter;
carouselSlide.style.transform = 'translateX(' + (-size * counter) + 'px)';
}
});
<div class="carousel-container">
<i class="fa fa-arrow-left" id="prevBtn" aria-hidden="true"></i>
<i class="fa fa-arrow-right" id="nextBtn" aria-hidden="true"></i>
<div class="carousel-slide">
<img src="public/images/homme.jpeg" id="lastClone" alt="">
<img src="public/images/homme.jpeg" alt="">
<img src="public/images/homme.jpeg" alt="">
<img src="public/images/homme.jpeg" alt="">
<img src="public/images/homme.jpeg" id="firstClone" alt="">
</div>
</div>
</div>
One option would be to place each image in the center of its own container div that has the size of the largest image, line up those divs, and have your carouselSlide slide over those divs, so that it only shows one div at a time.
This may produce margins for images that are smaller than the largest image. One way to solve that is to use CSS to set the images as background images of the divs, and use CSS to center the images and fill the div.

Setting Image Transition after Loading w/ JavaScript

I have two functions, one loads the mobile images in and the other automatically translates the images after a set time. The problem is that the translate function is no longer working after moving all image loading to JavaScript instead of hard-coding it in the HTML (due to webpack asset management and the build process). Here is the site for reference: https://ecstatic-snyder-29f00e.netlify.app/
Load Mobile Images
function loadMobileImages() {
const mobileArr = [img1, img2, img3, img4];
const imgTags = document.querySelectorAll('.mobileBackground');
const lastClone = document.querySelector('#lastClone');
const firstClone = document.querySelector('#firstClone');
lastClone.src = img4;
firstClone.src = img1;
for (let i=0; i<imgTags.length; i++) {
imgTags[i].src = mobileArr[i];
};
return new Promise(function(resolve, reject) {
setTimeout(backgroundSlideShow, 100);
});
};
Start Slide Show
function backgroundSlideShow() {
const container = document.querySelector('#carousel-container');
const carouselImgs = document.querySelectorAll('.background');
const slideTime = 10000;
let counter = 1;
const size = carouselImgs[0].clientWidth;
container.style.transform = 'translateX(' + (-size * counter) + 'px)';
setInterval(function() {
if (counter >= carouselImgs.length - 1) {
return
};
container.style.transition = 'transform 0.4s ease-in-out';
counter++;
container.style.transform = 'translateX(' + (-size * counter) + 'px)';
}, slideTime);
container.addEventListener('transitionend', () => {
if (carouselImgs[counter].id === 'firstClone') {
container.style.transition = 'none';
counter = carouselImgs.length - counter;
container.style.transform = 'translateX(' + (-size * counter) + 'px)';
}
});
};
Both functions are being called, but the slideshow doesn't start until loading the page and then refreshing. Does anyone know what may be causing this type of behavior? I read that setting CSS w/ JavaScript can mess with how things load, but am not sure how to remedy this when images need to be set with JavaScript or CSS. Currently using a setTimout function to prolong the transition.
Loading in images with css solved the issue. Also gave a performance boost on load times.

JavaScript - Restart setTimeout timer in a recursive function

I'm trying to make an automatic slideshow in css and js. I've got a function that infinitely loops through an array of images (in the slideshow) after a specified time.
function autoSlide(){
carouselSlide.style.transition = "transform 1s ease-in-out";
counter++;
carouselSlide.style.transform = 'translateX(' + (-size * counter) + 'px)';
t = setTimeout("autoSlide()", time);
}
But I want to reset the timer time if I manually change the slide by pressing a button. I tried this but it didn't work:
function autoSlide(){
carouselSlide.style.transition = "transform 1s ease-in-out";
counter++;
carouselSlide.style.transform = 'translateX(' + (-size * counter) + 'px)';
nextBtn.addEventListener('click',()=>{
clearTimeout(t);
})
t = setTimeout("autoSlide()", time);
}
Any help would be much appreciated.
Thanks.
Please use setInterval instead of setTimeout.
Like this:
function autoSlide(){
carouselSlide.style.transition = "transform 1s ease-in-out";
counter++;
carouselSlide.style.transform = 'translateX(' + (-size * counter) + 'px)';
}
var t = setInterval(autoSlide, time)
nextBtn.addEventListener('click',()=>{
clearInterval(t);
t= setInterval(autoSlide, time)
})
I don't see that you're defining the interval variable outside of the function scope so it might be getting lost. Also, shouldn't this be a setInterval vs setTimeout? You could use either, but if your goal is to infinitely repeat until some condition, setInterval is more appropriate
let interval = setInterval(autoSlide, time); // variable being initialized outside function scope
nextBtn.addEventListener('click',()=>{
clearInterval(interval);
interval = setInterval(autoSlide, time)
})
function autoSlide(){
carouselSlide.style.transition = "transform 1s ease-in-out";
counter++;
carouselSlide.style.transform = 'translateX(' + (-size * counter) + 'px)';
// ... presumably other logic to progress your slideshow every 'time'
}
One way to do it would be to recreate the timer when you click. Not only delete the timer, but also recreate it.
nextBtn.addEventListener('click',()=>{
clearTimeout(t);
t = setTimeout(autoSlide, time);
})
ps: it's always good to learn, but dont try too much to reinvent the wheel.
use this for exemple : https://owlcarousel2.github.io/OwlCarousel2/demos/basic.html
responseive, auto, touch support, etc...
If this is a carousel you want your timeout to be the same but to reset the counter when you click the button.
Here's a function that sets up your timer, and your button, and returns a closure (a function that retains the information in its preceding lexical environment after it's been returned) that controls the timeout.
function handler() {
const time = 1000;
let counter = 0;
const button = document.addEventListener('click', () => counter = 0);
return function loop() {
// Your transform code goes here
console.log(counter);
counter++;
setTimeout(loop, time);
}
}
// autoSlide is the returned function
const autoSlide = handler();
autoSlide();
<button>Stop the sliding!</button>

How to make my automatic image carousel loop back to the first image without exposing the second one

I am currently working on an Image carousel and it appears that I have ran into a problem. The carousel(there are three images) works well automatically but instead of it looping back to the first image, it goes all the way back to the first one exposing the second image for a brief moment. How could I get the carousel to make a complete loop without it exposing the second image in the process? Here is my code.
HTML
...<div class="carousel-container">
<i class="fa fa-angle-left" id="prevBtn"></i>
<i class="fa fa-angle-right" id="nextBtn"></i>
<div class="carousel-slide">
<img src="./img/testpic3.jpg" id="lastClone" alt="">
<img src="./img/testpic1.jpg" alt="">
<img src="./img/testpic2.jpg" alt="">
<img src="./img/testpic3.jpg" alt="">
<img src="./img/testpic1.jpg" id="firstClone" alt="">
</div>
</div>
const carouselSlide = document.querySelector('.carousel-slide');
const carouselImages = document.querySelectorAll('.carousel-slide img');
const prevBtn = document.querySelector('#prevBtn');
const nextBtn = document.querySelector('#nextBtn');
let counter = 1;
const size = carouselImages[0].clientWidth;
carouselSlide.style.transform = 'translateX(' + (-carouselImages[0].clientWidth * counter) + 'px)';
var interval = 5000;
setInterval(function() {
var offset = counter % (carouselImages.length - 2);
carouselImages[counter].id === 'firstClone';
carouselSlide.style.transition = "transform 0.4s ease-in-out";
carouselSlide.style.transform = 'translateX(' + (-carouselImages[0].clientWidth * counter) + 'px)';
counter++;
if (offset == 0) counter = 1; // to reset counter so next and prev button should work
}, interval);
nextBtn.addEventListener('click', () => {
if (counter >= carouselImages.length - 1) return;
carouselSlide.style.transition = "transform 0.4s ease-in-out";
counter++;
carouselSlide.style.transform = 'translateX(' + (-carouselImages[0].clientWidth * counter) + 'px)';
// console.log(counter);
});
prevBtn.addEventListener('click', () => {
if (counter <= 0) return;
carouselSlide.style.transition = "transform 0.4s ease-in-out";
counter--;
carouselSlide.style.transform = 'translateX(' + (-carouselImages[0].clientWidth * counter) + 'px)';
// console.log(counter);
});
carouselSlide.addEventListener('transitionend', () => {
console.log(carouselImages[counter]);
if (carouselImages[counter].id === 'lastClone') {
carouselSlide.style.transition = "none";
counter = carouselImages.length - 2;
carouselSlide.style.transform = 'translateX(' + (-size * counter) + 'px)';
}
if (carouselImages[counter].id === 'firstClone') {
carouselSlide.style.transition = "none";
counter = carouselImages.length - counter;
carouselSlide.style.transform = 'translateX(' + (-size * counter) + 'px)';
}
});
JavaScript:
const carouselSlide = document.querySelector('.carousel-slide');
const carouselImages = document.querySelectorAll('.carousel-slide img');
const prevBtn = document.querySelector('#prevBtn');
const nextBtn = document.querySelector('#nextBtn');
let counter = 1;
const size = carouselImages[0].clientWidth;
carouselSlide.style.transform = 'translateX(' + (-carouselImages[0].clientWidth * counter) + 'px)';
var interval = 5000;
setInterval(function() {
var offset = counter % (carouselImages.length - 2);
carouselImages[counter].id === 'firstClone';
carouselSlide.style.transition = "transform 0.4s ease-in-out";
carouselSlide.style.transform = 'translateX(' + (-carouselImages[0].clientWidth * counter) + 'px)';
counter++;
if (offset == 0) counter = 1; // to reset counter so next and prev button should work
}, interval);
nextBtn.addEventListener('click', () => {
if (counter >= carouselImages.length - 1) return;
carouselSlide.style.transition = "transform 0.4s ease-in-out";
carouselSlide.style.transform = 'translateX(' + (-carouselImages[0].clientWidth * counter) + 'px)';
// console.log(counter);
});
prevBtn.addEventListener('click', () => {
if (counter <= 0) return;
carouselSlide.style.transition = "transform 0.4s ease-in-out";
counter--;
//carouselSlide.style.transform = 'translateX(' + (-size * counter) + 'px)';
carouselSlide.style.transform = 'translateX(' + (-carouselImages[0].clientWidth * counter) + 'px)';
// console.log(counter);
});
carouselSlide.addEventListener('transitionend', () => {
console.log(carouselImages[counter]);
if (carouselImages[counter].id === 'lastClone') {
carouselSlide.style.transition = "none";
counter = carouselImages.length - 2;
carouselSlide.style.transform = 'translateX(' + (-size * counter) + 'px)';
}
if (carouselImages[counter].id === 'firstClone') {
carouselSlide.style.transition = "none";
counter = carouselImages.length - counter;
carouselSlide.style.transform = 'translateX(' + (-size * counter) + 'px)';
}
});
Thanks!
To be honest your codes look complicated. You can simply use this.
<div id="demo" class="carousel slide" data-ride="carousel">
<!-- Indicators -->
<ul class="carousel-indicators">
<li data-target="#demo" data-slide-to="0" class="active"></li>
<li data-target="#demo" data-slide-to="1"></li>
<li data-target="#demo" data-slide-to="2"></li>
</ul>
<!-- The slideshow -->
<div class="carousel-inner">
<div class="carousel-item active">
<img src="la.jpg" alt="Los Angeles" width="1100" height="500">
</div>
<div class="carousel-item">
<img src="chicago.jpg" alt="Chicago" width="1100" height="500">
</div>
<div class="carousel-item">
<img src="ny.jpg" alt="New York" width="1100" height="500">
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#demo" data-slide="prev">
<span class="carousel-control-prev-icon"></span>
</a>
<a class="carousel-control-next" href="#demo" data-slide="next">
<span class="carousel-control-next-icon"></span>
</a>
</div>
With this, your carousel will loop everytime it reaches the end of your carousel. Or you can check the example here.

Categories

Resources