0

I need help getting my image slideshow to work properly. I set it up to loop over an array of images and display each one in 5 second intervals. What it actually does is loop over the entire array but only displays the last image. Code below:

const imgArray = ['http://media.tumblr.com/tumblr_lf88gg6J5d1qamm7n.jpg',
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR5SG1QIHcwLM9FNPFOO0IvFBNJ9CJCGZ-iGz7zfmfhTypEqqTU','https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQRZLiRBwwBBMAapL5IzxqoV-zskYuGD9lWvyirUryKjVaRqwlO'];
let index = 0;

function autoChange() {
  let img = document.getElementById('img');
  let arrayIndex;
  for (arrayIndex = 0; arrayIndex < imgArray.length; arrayIndex++) {
    img.src = imgArray[arrayIndex];
    setTimeout(autoChange, 3000);
    console.log(imgArray[arrayIndex]);
  }
  arrayIndex++;
  if(arrayIndex > imgArray.length) {
    arrayIndex = 0
  };
}

autoChange();
<section>
  <figure>
    <img id='img' class='displayed-img' width="350" src="imgs/pic0.jpg">
  </figure>
</section>

Thank you.

6
  • On each autoChange() request you are looping over all the images, which in turn leads to all the images being loaded very quickly but ending on the last one. And this is what you are seeing. What you need to do is keep track of the image that is load, check for the next one and load that. If no next image, go back to the start (hint: no loop needed). Commented Jun 10, 2018 at 23:43
  • @baao yes, you're right! Commented Jun 10, 2018 at 23:44
  • The issue is that you might expect the setTimeout to be blocking, meaning it’ll wait the three seconds before continuing with the next iteration, which it will not. Commented Jun 10, 2018 at 23:45
  • you will always have the last value simply because after 3 seconds index will be incremented. you can use closure in this situation. Commented Jun 10, 2018 at 23:56
  • @Stakvino index is never actually used in the OPs code beyond initializing it to 0 so it will stay 0 the entire time. arrayIndex will become 3 almost immediately (not after 3 seconds). Commented Jun 11, 2018 at 0:36

2 Answers 2

0

JavaScript runs in a single-threaded environment (only one task can be executing at any given moment). You are trying to "slow down" your loop with a timer, but the timer's callback function will only execute after the current function (and all other code on the call stack) have finished. So, your loop runs to completion and then the timer is called.

As such, you shouldn't try to use a timer inside of a loop. Instead, keep a counter outside of the scope of your function and increment it upon each function call. Then, have the timer call the function all over again - this creates the looping effect you are looking for without the actual loop.

const imgArray = ['http://media.tumblr.com/tumblr_lf88gg6J5d1qamm7n.jpg',
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR5SG1QIHcwLM9FNPFOO0IvFBNJ9CJCGZ-iGz7zfmfhTypEqqTU','https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQRZLiRBwwBBMAapL5IzxqoV-zskYuGD9lWvyirUryKjVaRqwlO'];

let index = 0;  // This will keep track of the current array index to use
let img = document.getElementById('img'); // Get your reference just once, not on each function call

function autoChange() {
  // You only need to ensure that the index isn't out of bounds
  if(index < imgArray.length){
    img.src = imgArray[index];      // If not, use the index
    index++;                        // Then, increment it
    console.clear();
    console.log(imgArray[index]);
  } else {
    index = 0;  // If so, reset the index
  }
  // Now that the right image is showing, wait 3 seconds and call the function all over again
  setTimeout(autoChange, 3000);  
}

autoChange();
<section>
  <figure>
    <img id='img' class='displayed-img' width="350" src="imgs/pic0.jpg">
  </figure>
</section>

Sign up to request clarification or add additional context in comments.

3 Comments

Explain the down vote
Thank you very much for the solution and the explanation! I do not have the ability to down vote yet and I don't know why someone would have.
I don't understand the downvote either, and you gave me an idea of how to solve my issue, so I upvoted you.
-2

you were at the right track, made little changes

const imgArray = ['http://media.tumblr.com/tumblr_lf88gg6J5d1qamm7n.jpg',
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR5SG1QIHcwLM9FNPFOO0IvFBNJ9CJCGZ-iGz7zfmfhTypEqqTU','https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQRZLiRBwwBBMAapL5IzxqoV-zskYuGD9lWvyirUryKjVaRqwlO'];
var index = 0;

function autoChange() {
  let img = document.getElementById('img');
  if (index >= imgArray.length)
  index = 0;
  else index++
  
 img.src= imgArray[index] 

 setTimeout(autoChange, 3000);
}

autoChange();
<section>
  <figure>
    <img id='img' class='displayed-img' width="350" src="imgs/pic0.jpg">
  </figure>
</section>

3 Comments

Answers on Stack Overflow should explain the problem and the proposed solution. Additionally, poor coding habits in answers should be avoided. You are omitting the brackets {} around your if branches and some semi-colons. While legal syntax, both are well known to be bad practices as they both can lead to bugs.
man you are to much, np for down voting
man you are to much As long as that is your point of view, I think your "answers" will continue to be down voted. Try to understand what Stack Overflow actually is..

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.