0

I want to create a function to animate text like typewriter. I can't understand why words[index].length is returning undefined in setInterval funcation.

let speed = Math.floor(Math.random() * 1000); 

function typeWriter() {
    let words = ["Achieve", "Attain"]; /* The text */ // 6

    let typeWriter = document.getElementById("typewriter");
    let i = 1;
    let index = 0;
    while (index < words.length) {

        setInterval(() => {

            if (i <= words[index].length && i > 0) {
                typeWriter.innerHTML = words[index].slice(0, i);

                if (i == words[index].length) {
                    i = -1;
                }else {
                    i++;
                }
            } else if ((i * -1) <= words[index].length && i < 0) {
                typeWriter.innerHTML = words[index].slice(0, i);

                if ((i * -1) == words[index].length) {
                    clearInterval();
                }else {
                    i--;
                }
            }

            speed = Math.floor(Math.random() * 1000);

       }, speed);

       if (index == words.length) {
           index = 0;
       } else {
           index++
       }
    }
}
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
Talha Meer
  • 31
  • 1
  • 5
  • Does this answer your question? [JavaScript closure inside loops – simple practical example](https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – Sebastian Simon Jul 15 '20 at 10:27
  • `words[index].length` is not returning undefined. Read the error message carefully. `words[index]` is undefined. Please try using the [debugging capabilities](https://developer.mozilla.org/en-US/docs/Mozilla/Debugging/Debugging_JavaScript) of your browser. `index` is `2` by the time any of your `setInterval` callbacks are executed. Please also see [How do I add a delay in a JavaScript loop?](https://stackoverflow.com/q/3583724/4642212). – Sebastian Simon Jul 15 '20 at 10:30

1 Answers1

0

You have a problem with a closure on setInterval function.

while (index < words.length) {
    const word = words[index]; // fetch word from the array as a constant
    setInterval(() => {

        if (i <= word.length && i > 0) {
            typeWriter.innerHTML = word.slice(0, i); // use word reference

    ...

You need to fetch the value to a constant before calling setInterval, then use it. Because all code is inside of a single block of code, your index variable is modified before setInterval block is executed. So you need to make your setInnterval code execution be independent from index variable.

Second solution would be to move your setInterval to second function, that receives index as a parameter. That way, index value would be copied and not change inside of this block, even if original value will change.

Beri
  • 11,470
  • 4
  • 35
  • 57