JS setInterval() help

I’m trying to use setInterval() to change the text or quotes in a paragraph. It seems to go off but then I get "undefined in the text box instead of the quote I want to replace the old one with. Any help at all would be greatly appreciated .
Code:

let quotes = [
  { quote: "This is quote number two" },
  { quote: "this is quote number three" },
];

const para = document.getElementById("para");

function changeQuote() {
  for (i = 0; i < quotes.length; i++) {
    setInterval(function () {
      para.innerHTML = '<span>"</span>' + quotes[i] + "<span>";
    }, 2000);
  }
}

changeQuote();

HTML:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="box">
      <p id="para">This is the paragraph I need to change.</p>
    </div>

    <script src="app.js"></script>
  </body>
</html>

Right, this is a classic problem with scopes and closures. Bu the time your callback is run, i has ++ed its way to 2, which is undefined in this array. You can find explanations online, like here. Take a look and if it still doesn’t make sense, check back.

3 Likes

I see that you tried to use backticks ` but your sytax was a bit off for multi line code blocks.

When you enter a code block into a forum post, please precede it with a separate line of three backticks and follow it with a separate line of three backticks to make it easier to read.

Please use the “preformatted text” tool in the editor (</>) to add backticks around text.

See this post to find the backtick on your keyboard.
Note: Backticks are not single quotes.

markdown_Forums

1 Like

It sort of makes sense, the outer loop has already been executed by the time the interval has passed. I used a solution in that article but now I’m getting [object, Object] returned:

  { quote: "This is quote number two" },
  { quote: "this is quote number three" },
];

const para = document.getElementById("para");

for (let i = 0; i < quotes.length; i++) {
  setInterval(function () {
    para.innerHTML = quotes[i];
  }, 2000);
}

Sure, there are different ways to solve it. This is one of the cleaner ones made possible with ES6. But this is a common interview question - it would be good to be familiar with them all.

1 Like

Thanks yeah I’m definitely going to do some more reading on it. Apparently that’s the solution but it doesn’t quite work in my case, returning [object, Object] rather than the actual quote from the array. At least now I have a better of idea of what’s going on though.

You did wrap your quotes inside of objects, which means if you print something from the quote array, you’ll be printing the quote object. To get the text of the quote object you’ll need to access the "quote" property.

2 Likes

The issue is your data structure. Since you have an array of objects you should be using quotes[i].quote

1 Like

If you eliminated the objects and just used strings you wouldn’t have to attach the .quote to access a property.

let quotes = [ "This is quote number two", "this is quote number three" ];

1 Like

Right that was a remnant from when I had several key value pairs in the objects instead of just one. Thanks!

1 Like

No problem! I take it you got things working?

It’s working a little better but now it’s jumping straight to the second quote in the array. Any idea why?

It isn’t returning undefined anymore but it jumps straight to the second quote in the array.


const quotes = ["This is quote number two", 
"This is quote number three"];

const para = document.getElementById("para");

for (let i = 0; i < quotes.length; i++) {
  setInterval(function () {
    para.innerHTML = quotes[i];
  }, 2000);
}

I guess it would help having a bit more context. Are you trying to have it run nonstop or change a few times?

For now I just want it to show every quote in the array one by one until there are no more and then either stop or cycle through again. Right now though I’m mostly just concerned about it cycling through each quote in the array and returning it in the browser. The project that spawned this was going to be a French word of the day website that updated automatically every 24 hours but can also be scrolled through. But one problem at a time lol

1 Like

Closures are tricky but something like this can get you the result you’re looking for.
`

const quotes = [
“Bonjour = Hello, Good morning.”,
“Au revoir = Goodbye.”,
“Oui = Yes.”,
“Non = No.”,
“Merci = Thank you.”,
“Merci beaucoup = Thank you very much.”,
];

const para = document.getElementById(“para”);

for (let i = 0; i < quotes.length; i++) {
(function(i) {
setTimeout(function() {
para.innerHTML = quotes[i];
}, 3000 * i);
})(i);
}

`

Also here is a link to a pen with some code you shared and what I edited

https://codepen.io/brendanpettis/pen/QWyyZdv

1 Like

If you still want to use setInterval, you could do something like:

const quotes = [
  "This is quote number one", 
  "This is quote number two", 
  "This is quote number three",
  "This is quote number four"
];

const updateQuote = quote => {
   para.innerHTML = quote;
};

const para = document.getElementById("para");

let i = 0;
updateQuote(quotes[i]); // updates with first quote
setInterval(() => {
  i = i < quotes.length - 1 ? i + 1 : 0; // set i to 0 when last quote displayed, otherwise increment by one
  updateQuote(quotes[i]);
}, 2000);
1 Like

Sorry, I should have looked closer.

1 Like

Yeah that works for what I’m trying to accomplish right atm, thanks. I don’t understand exactly how it works though, specifically the milliseconds argument * i lol