It can be quite complicated to refactor the carousel since there are many moving parts. We’ll go through them together in a few lessons.
We’ll go from top to bottom to make things easier to explain.
Setting the position of all slides
We used this code to set the initial position of our slides:
const slideWidth = slides[0].getBoundingClientRect().widthslides.forEach((slide, index) => { slide.style.left = slideWidth * index + 'px'})This code is imperative. We had to read through the code to understand what it does. If we put this code into a function like setSlidePositions, we will know what the code does without even looking at it.
function setSlidePositions() { const slideWidth = slides[0].getBoundingClientRect().width slides.forEach((slide, index) => { slide.style.left = slideWidth * index + 'px' })}Using the setSlidePositions:
setSlidePositions()The nextButton event listener
Code for the nextButton’s event listener is quite complicated. We did five things here:
- Gets
currentSlide,nextSlideanddestination - Shows
nextSlideby changing thetransformproperty - Shows
previousButton - Hides
nextButtonif next slide is the last slide - Highlights the next dot
nextButton.addEventListener('click', event => { const currentSlide = contents.querySelector('.is-selected') const nextSlide = currentSlide.nextElementSibling const destination = getComputedStyle(nextSlide).left
// Shows next slide contents.style.transform = `translateX(-${destination})` currentSlide.classList.remove('is-selected') nextSlide.classList.add('is-selected')
// Shows previous button previousButton.removeAttribute('hidden')
// Hides next button if (!nextSlide.nextElementSibling) { nextButton.setAttribute('hidden', true) }
// Highlight dot const currentDot = dotsContainer.querySelector('.is-selected') const nextDot = currentDot.nextElementSibling currentDot.classList.remove('is-selected') nextDot.classList.add('is-selected')})The code for previousButton’s event listener is similar. We did the same five things:
- Gets
currentSlide,previousSlideanddestination - Shows
previousSlideby changing thetransformproperty - Shows
nextButton - Hides
previousButtonif previous slide is the first slide - Highlights the previous dot
previousButton.addEventListener('click', event => { const currentSlide = contents.querySelector('.is-selected') const previousSlide = currentSlide.previousElementSibling const destination = getComputedStyle(previousSlide).left
// Shows previous slide contents.style.transform = `translateX(-${destination})` currentSlide.classList.remove('is-selected') previousSlide.classList.add('is-selected')
// Shows next button nextButton.removeAttribute('hidden')
// Hides previous button if (!previousSlide.previousElementSibling) { previousButton.setAttribute('hidden', true) }
// Highlight dot const currentDot = dotsContainer.querySelector('.is-selected') const previousDot = currentDot.previousElementSibling currentDot.classList.remove('is-selected') previousDot.classList.add('is-selected')})There are two parts that are similar in these two sets of code:
- The part for switching slides
- The part for highlighting the dot
Refactoring the part for switching slides
We wrote this code to switch to the next slide:
// Shows next slidecontents.style.transform = `translateX(-${destination})`currentSlide.classList.remove('is-selected')nextSlide.classList.add('is-selected')And we wrote this code to switch to the previous slide:
// Shows previous slidecontents.style.transform = `translateX(-${destination})`currentSlide.classList.remove('is-selected')previousSlide.classList.add('is-selected')These two sets of code are similar. We can group them into a function called switchSlide.
function switchSlide() { // ...}The easiest way to build switchSlide is first to copy/paste the code we need into the function.
function switchSlide() { // Shows next slide contents.style.transform = `translateX(-${destination})` currentSlide.classList.remove('is-selected') nextSlide.classList.add('is-selected')
// Shows previous slide contents.style.transform = `translateX(-${destination})` currentSlide.classList.remove('is-selected') previousSlide.classList.add('is-selected')}Here, we know we need three things:
- The
currentSlide - The slide we want to move to (either
nextSlideorpreviousSlide). We’ll call thistargetSlide. - The
destination(theleftproperty of the slide we want to move to).
We can pass these properties into the function as arguments:
function switchSlide(currentSlide, targetSlide, destination) { contents.style.transform = `translateX(-${destination})` currentSlide.classList.remove('is-selected') targetSlide.classList.add('is-selected')}If you noticed, we can get destination from targetSlide. This means we can pass in one less variable. We’ll get destination within switchSlide.
function switchSlide(currentSlide, targetSlide) { const destination = getComputedStyle(targetSlide).left contents.style.transform = `translateX(-${destination})` currentSlide.classList.remove('is-selected') targetSlide.classList.add('is-selected')}Using switchSlide:
nextButton.addEventListener('click', event => { const currentSlide = contents.querySelector('.is-selected') const nextSlide = currentSlide.nextElementSibling
switchSlide(currentSlide, nextSlide)
// ...})previousButton.addEventListener('click', event => { const currentSlide = contents.querySelector('.is-selected') const previousSlide = currentSlide.previousElementSibling
switchSlide(currentSlide, previousSlide)
// ...})Highlighting dots
Here’s the code we used to highlight the next dot:
nextButton.addEventListener('click', event => { // ... // Highlight dot const currentDot = dotsContainer.querySelector('.is-selected') const nextDot = currentDot.nextElementSibling currentDot.classList.remove('is-selected') nextDot.classList.add('is-selected')})And the code to highlight the previous dot:
previousButton.addEventListener('click', event => { // ... // Highlight dot const currentDot = dotsContainer.querySelector('.is-selected') const previousDot = currentDot.previousElementSibling currentDot.classList.remove('is-selected') previousDot.classList.add('is-selected')})Again, these two sets of code are similar. We can use the same technique as switchSlides to build a function for them. Let’s call this function highlightDot.
function highlightDot() { // ...}First, we copy/paste everything we need into hightlightDot.
function highlightDot() { // Highlight next dot const currentDot = dotsContainer.querySelector('.is-selected') const nextDot = currentDot.nextElementSibling currentDot.classList.remove('is-selected') nextDot.classList.add('is-selected')
// Highlight previous Dot const currentDot = dotsContainer.querySelector('.is-selected') const previousDot = currentDot.previousElementSibling currentDot.classList.remove('is-selected') previousDot.classList.add('is-selected')}We can see we need two variables:
- The
currentDot - The
targetDot(eitherpreviousDotornextDot)
We can pass these two variables into hightlightDot.
function highlightDot(currentDot, targetDot) { currentDot.classList.remove('is-selected') targetDot.classList.add('is-selected')}Using highlightDot:
nextButton.addEventListener('click', event => { // ... const currentDot = dotsContainer.querySelector('.is-selected') const nextDot = currentDot.nextElementSibling
highlightDot(currentDot, nextDot) // ...})previousButton.addEventListener('click', event => { // ... const currentDot = dotsContainer.querySelector('.is-selected') const previousDot = currentDot.previousElementSibling
highlightDot(currentDot, previousDot)})What’s left from nextButton and previousButton event handlers are the part where we show/hide previous and next buttons.
Showing/hiding previous and next buttons
Here’s the code we wrote for the showing/hiding the previous and next buttons:
nextButton.addEventListener('click', event => { // ... // Shows previous button previousButton.removeAttribute('hidden')
// Hides next button if (!nextSlide.nextElementSibling) { nextButton.setAttribute('hidden', true) }})previousButton.addEventListener('click', event => { // ... // Shows next button nextButton.removeAttribute('hidden')
// Hides previous button if (!previousSlide.previousElementSibling) { previousButton.setAttribute('hidden', true) }})It seems like there are no commonalities between these two sets of code. We can’t refactor them at this point.
You’ll start to see the commonalities between these two sets of code when we refactor the dots part in the next lesson.
Welcome! Unfortunately, you don’t have access to this lesson. To get access, please purchase the course or enroll in Magical Dev School.
Unlock this lesson