Problem - Image and slider dot is out of sync

Hi there! I just recently completed the basics of HTML, CSS, and Javascript. Now, I am trying to clone the home page of this website: https://www.startech.com.bd/. But I have run into a small problem. The webpage has an image slider, where the image changes every 5 seconds, and there are also three dots representing those three images, respectively.

Here is my code -

HTML

      <div class="image-responsive-div">
        <img class="image-responsive" data-image-responsive src="./resources/images/09-09-24a-v4-(antec-C8-offer-web-banner-design)-982x500.jpg"/>
        <img class="image-responsive" data-image-responsive src="./resources/images/express-delivery-girl-receiving-parcel-home-banner-982x500.webp"/>
        <img class="image-responsive" data-image-responsive src="./resources/images/queue-banner-home-service-982x500.png"/>

        <div class="slider-dot">
          <span class="dot" data-dot></span>
          <span class="dot" data-dot></span>
          <span class="dot" data-dot></span>
        </div>
      </div>

CSS

.image-responsive-div{
    position: relative;
    width: 990px;
    height: 490px;
    padding: 0px 15px;
}

.image-responsive{
    width: 960px;
    height: 488px;
    position: absolute;
    box-shadow: 0 0.5px 4px 0 rgba(0, 0, 0, 0.3);
}

.slider-dot{
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    text-align: center;
    padding: 10px 0;
}

.dot{
    display: inline-block;
    width: 30px;
    height: 8px;
    background: #fff;
    margin: 0 5px;
    opacity: .5;
    cursor: pointer;

}

Javascript

const imageResponsive = document.querySelectorAll('[data-image-responsive]');
const dot = document.querySelectorAll('[data-dot]');


let counter = 0;



function changeImage(){

    // First hide all images
    imageResponsive.forEach(img => img.style.display = 'none');

    // Show the current image based on the counter value
    imageResponsive[counter].style.display = 'block';

    // First hide all slider dots
    dot.forEach((span) => {
        span.style.background = '#fff';
        span.style.opacity = '0.5';    
    });
    // Show the current slider dot based on the counter value
    dot[counter].style.background = '#ef4a23';
    dot[counter].style.opacity = '1';  

    // Increment counter and reset if it exceeds the length of the image array
    counter = (counter + 1) % imageResponsive.length;

    
}



// Start the image change every 5 seconds
setInterval(changeImage, 5000);


// Initially display the first image and the slider dot
imageResponsive[0].style.display = 'block';
dot[0].style.background = '#ef4a23';
dot[0].style.opacity = '1';

But the problem is with the slider. When the website loads, the first image and the first slider load up correctly, but then, when the second image comes, the slider still stays in first place. And when the third image comes, the slider moves to second place. Why is that?

I also tried asking Chatgpt but still did not understand what it said. Anyway, here is its answer: " The issue is happening because your counter is incremented after the images and dots are updated. This causes a delay in the slider dot movement. On the first run, the first image and first dot are shown correctly, but when the counter increments after updating the image for the second time, the dot update is out of sync with the image."

So, can someone explain why the slider and the image are out of sync during the 2nd run?

Thank you so much for your attention and participation.

The issue is probably going to come down to when the event loop triggers different parts of that function. You’re doing several things at once inside the same function. What I would suggest is to utilize good separation of concerns, and break that function up into smaller helper functions.

For example, you can move the counter logic into a helper function called incrementCounter, and then call it with your changeImage function. That way the counter increment is explicitly called and returned.

SetInterval is also asynchronous by its nature, so that could be another issue. You’re essentially mixing synchronous and asynchronous code here.

In other words-- all of the stuff in your changeImage function triggers at once, and SetInterval is probably not ready for that to happen.

So in summary, use helper functions, and if that doesn’t work, you may need to use async promises in order to make sure that specific things happen in a particular order

1 Like

I found the solution.

I posted the same question here and at Stack Overflow (javascript - Image and slider dot is out of sync - Stack Overflow). Someone at Stack Overflow pointed out what the actual problem was.

The problem is that all images are shown at once before the timer is run for the first time. So, all the images stack on top of each other, with the last one on top.

Here’s what happens -

  • when the website loads, the 3rd image + 1st dot is shown.
  • after 5 seconds, the 1st image + 1st dot is shown.

Which made it seem like the image and dot were out of sync.

Here’s the solution -

CSS

.image-responsive{
    width: 960px;
    height: 488px;
    display: none;
    position: absolute;
    box-shadow: 0 0.5px 4px 0 rgba(0, 0, 0, 0.3);
}

Added display:none; to make sure when the website loads, the 1st image and 1st dot is shown.

Javascript

let counter = 1;

The counter variable should be 1 instead of 0. Since if the counter is set to 0, by default the 1st image + 1st dot loads up. And after 5 seconds, again the 1st image + 1st dot loads up. So it takes 10 seconds instead of 5 seconds to move to the second image.