Stop carousel slideshow when previous button is clicked

I have a div that contains 4 divs. There is an autoSlide() function that makes the slides move forward every 3s, a next and a prev button.

Everything works fine, but when I click the prev button I want the auto slide to stop, go back to the previous slide and restart the auto slide again.

I managed to stop the timer but I don’t know how to restart the auto slide.

HTML:

<div class="slides-wrapper">
  <div class="slide">1</div>
  <div class="slide">2</div>
  <div class="slide">3</div>
  <div class="slide">4</div>
</div>
<button class="prev">Prev</button>
<button class="next">Next</button>

CSS:

.slides-wrapper {
  position: relative;
  height: 100vh;
}

.slide {
  position: absolute;
  border: 1px solid black;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 5rem;
}

.prev {
  position: fixed;
  top: 50%;
}

.next {
  position: fixed;
  top: 50%;
  right: 5px;
  z-index: 10;
}

JS:

const prevButton = document.querySelector('.prev');
const nextButton = document.querySelector('.next');
const slides = document.querySelectorAll('.slide');

slides.forEach((slide, index) => {
  slide.style.transform = `translateX(${index * 100}%)`;
});

let currentSlide = 0;
let maxSlide = slides.length - 1;
let timer;

function autoSlide() {
  if(currentSlide === maxSlide) {
    currentSlide = 0;
  } else {
    currentSlide++;
  }

  // Move slides to the left //
  slides.forEach((slide, index) => {
     slide.style.transform = `translateX(${100 * (index - currentSlide)}%)`;

   });
    
  timer = setTimeout(autoSlide, 3000);
}


nextButton.addEventListener('click', () => {

// Reset timeout //
  if (timer) {
    clearTimeout(timer);
  }
  
  autoSlide();
})

prevButton.addEventListener('click', () => {
  if (timer) {
    clearTimeout(timer);
  }
  
  if(currentSlide == 0) {
    currentSlide = maxSlide;
  } else {
    currentSlide--;
  }

  // Move slides to the right //
  slides.forEach((slide, index) => {
     slide.style.transform = `translateX(${100 * (index - currentSlide)}%)`;
   });      
})

autoSlide();

One way to do it would be to add a setTimeout(autoslide, 3000) after the forEach in the prevButton.addEventListener callback.

NOTE: Not sure if you noticed, but your slides start at 2 instead of 1 when the page loads.

EDIT: My suggestion above does not work. However, since autoslide is currently designed to increment currentSlide, then for your prevButton to work, you will need to decrement an extra 1 off it, so when it increments it, the correct slide will show.

Also, I see a lot of duplicate code that you could simply write once in the autoSlide function. You still need to fix the bug of the first slide showing slide 2, but I will leave that one for you.

const prevButton = document.querySelector(".prev");
const nextButton = document.querySelector(".next");
const slides = document.querySelectorAll(".slide");

let currentSlide = 0;
let maxSlide = slides.length - 1;
let timer;

function autoSlide() {
  if (timer) {
    clearTimeout(timer);
  }
  if (currentSlide === maxSlide) {
    currentSlide = 0;
  } else {
    currentSlide++;
  }

  // Move slides to the left //
  slides.forEach((slide, index) => {
    slide.style.transform = `translateX(${100 * (index - currentSlide)}%)`;
  });

  timer = setTimeout(autoSlide, 3000);
}

nextButton.addEventListener("click", () => {
  autoSlide();
});

prevButton.addEventListener("click", () => {
  if (currentSlide == 0) {
    currentSlide = maxSlide - 1;
  } else {
    currentSlide -= 2;
  }
  autoSlide()
});

autoSlide();

Thanks Randell, it works now:

let currentSlide = 0;
let maxSlide = slides.length - 1;
let timer;

// Positioning slides after page load
function autoSlide() {
  slides.forEach((slide, index) => {
  slide.style.transform = `translateX(${index * 100}%)`;
});
 timer = setTimeout(moveForward, 3000);  
}

function moveForward() {

  if(currentSlide === maxSlide) {
    currentSlide = 0;
  } else {
    currentSlide++;
  }
     // Move slides to the left //
  slides.forEach((slide, index) => {
     slide.style.transform = `translateX(${100 * (index - currentSlide)}%)`;
   });

   timer = setTimeout(moveForward, 3000);
}

nextButton.addEventListener('click', () => {
  clearTimeout(timer); 
  moveForward();
})

prevButton.addEventListener('click', () => {
  clearTimeout(timer);

  if(currentSlide == 0) {
    currentSlide = maxSlide;
  } else {
    currentSlide--;
  }

 // Move slides to the right
  slides.forEach((slide, index) => {
     slide.style.transform = `translateX(${100 * (index - currentSlide)}%)`;
   }); 

  timer = setTimeout(moveForward, 3000);
})

window.onload = autoSlide();

You still have similar code in autoslide and moveForward.

How about something like the following to make the code DRY?

const prevButton = document.querySelector(".prev");
const nextButton = document.querySelector(".next");
const slides = document.querySelectorAll(".slide");

let currentSlide = 0;
let maxSlide = slides.length - 1;
let timer;

function autoSlide(startAtFirst) {
  clearTimeout(timer);
  slides.forEach((slide, index) => {
    const translateX = startAtFirst
      ? `translateX(${index * 100}%)`
      : `translateX(${100 * (index - currentSlide)}%)`;
    slide.style.transform = translateX;
  });
  timer = setTimeout(moveForward, 3000);
}

function moveForward() {
  currentSlide = currentSlide === maxSlide ? 0 : currentSlide + 1;
  autoSlide();
}

nextButton.addEventListener("click", moveForward);

prevButton.addEventListener("click", () => {
  currentSlide = currentSlide ? currentSlide - 1 : maxSlide;
  autoSlide();
});

window.onload = function () {
  autoSlide(true);
};