skip to Main Content

I stripped out everything and placed it in one HTML file so it’s easier to test just this part.

The goal here is for it to first type Wx then remove the x wait for a second, then type elcome.

The code now produces Wlcome, I tried many things but can’t get it to type the **Welcome** with the first e.

Please help

const element = document.querySelector('#typing-area');

let textToType = 'Welcome';
const delayTime = 1000;


const typingSpeed = 100;
let currentIndex = 0;

function typeLetter() {
  const currentText = element.innerHTML;

  if (currentIndex === 1) {
    element.innerHTML += 'x';
    setTimeout(removeX, 1000);
  } else {

    element.innerHTML = currentText + textToType[currentIndex];

    currentIndex++;

    if (currentIndex < textToType.length) {
      setTimeout(typeLetter, typingSpeed);
    }
  }
}


function removeX() {
  const currentText = element.innerHTML;
  element.innerHTML = currentText.slice(0, -1);
  currentIndex = 2;
  setTimeout(typeLetter, typingSpeed);
}


setTimeout(typeLetter, 500);
#typing-area::after {
  content: '';
  display: inline-block;
  width: 0.1em;
  animation: blink 1s infinite;
}

@keyframes blink {
  50% {
    opacity: 0;
  }
}
<!DOCTYPE html>
<html>

<head>
  <title>Typing Example</title>

</head>

<body>
  <div id="typing-area"></div>

</body>

</html>

3

Answers


  1. Do not modify your currentIndex (= 2), just add flag, that you already printed error out, so your next iteration continues as normal text:

    const element = document.querySelector('#typing-area');
    
    let textToType = 'Welcome';
    const delayTime = 1000;
    
    
    const typingSpeed = 100;
    let currentIndex = 0;
    let hasErrorTyped = false;
    
    function typeLetter() {
      const currentText = element.innerHTML;
    
      if (currentIndex === 1 && !hasErrorTyped) {
        element.innerHTML += 'x';
        setTimeout(removeX, 1000);
        hasErrorTyped = true;
      } else {
    
        element.innerHTML = currentText + textToType[currentIndex];
    
        currentIndex++;
    
        if (currentIndex < textToType.length) {
          setTimeout(typeLetter, typingSpeed);
        }
      }
    }
    
    
    function removeX() {
      const currentText = element.innerHTML;
      element.innerHTML = currentText.slice(0, -1);
      setTimeout(typeLetter, typingSpeed);
    }
    
    
    setTimeout(typeLetter, 500);
    #typing-area::after {
      content: '';
      display: inline-block;
      width: 0.1em;
      animation: blink 1s infinite;
    }
    
    @keyframes blink {
      50% {
        opacity: 0;
      }
    }
    <!DOCTYPE html>
    <html>
    
    <head>
      <title>Typing Example</title>
    
    </head>
    
    <body>
      <div id="typing-area"></div>
    
    </body>
    
    </html>
    Login or Signup to reply.
  2. I kind of made your code more clear using promises

    const element = document.querySelector('#typing-area');
    
    const typingSpeed = 100;
    
    type()
    
    async function type() {
      await wait(500)
      await typeLetters('Wx')
      await wait(1000)
      await removeLetters(1)
      await typeLetters('elcome')
    }
    
    function wait(ms) {
      return new Promise(r => setTimeout(r, ms))
    }
    
    async function typeLetters(letters) {
      for (const char of letters) {
        element.textContent += char
        await wait(typingSpeed)
      }
    }
    
    async function removeLetters(count) {
      for (let i = 0; i < count; i += 1) {
        element.textContent = element.textContent.slice(0, -1)
        await wait(typingSpeed)
      }
    }
    #typing-area::after {
      content: '';
      display: inline-block;
      width: 0.1em;
      animation: blink 1s infinite;
    }
    
    @keyframes blink {
      50% {
        opacity: 0;
      }
    }
    <!DOCTYPE html>
    <html>
    
    <head>
      <title>Typing Example</title>
    
    </head>
    
    <body>
      <div id="typing-area"></div>
    
    </body>
    
    </html>
    Login or Signup to reply.
  3. The problem you are having is that you are simply checking if the currentIndex === 1 every time. So the first run through it replaces the e with an x, and it would just do that every time. Your solution was to manually force the index to 2, which is why the letter is skipped over. Remember, indexes begin at 0!

    0 - W
    1 - e
    2 - l
    3 - c
    5 - o
    6 - m
    7 - e
    

    So when you manually force the index to be 2, that’s the letter right after the first e, so it was skipped over.


    So, what I’ve done below is just added a bit of "state tracking" with a hasTypedError boolean so that the branch of code that types the x only runs that first time. I also moved your currentIndex++ to be outside of the if statement so that it can increment for both branches, and I fixed the manual index reset in the removeX function to reset to the correct index now.

    const element = document.querySelector('#typing-area');
    
    let textToType = 'Welcome';
    const delayTime = 1000;
    
    const typingSpeed = 100;
    let currentIndex = 0;
    let hasTypedError = false;
    
    function typeLetter() {
      const currentText = element.innerHTML;
    
      if (currentIndex === 1 && !hasTypedError) {
        element.innerHTML += 'x';
        hasTypedError = true;
        setTimeout(removeX, 1000);
      } else {
    
        element.innerHTML = currentText + textToType[currentIndex];
    
        if (currentIndex < textToType.length - 1 ) {
          setTimeout(typeLetter, typingSpeed);
        }
      }
      currentIndex++;
      
      console.log('type', currentIndex, element.innerHTML)
    }
    
    
    function removeX() {
      const currentText = element.innerHTML;
      element.innerHTML = currentText.slice(0, -1);
      currentIndex = 1
      setTimeout(typeLetter, typingSpeed);
      
      console.log('remove', currentIndex, element.innerHTML)
    }
    
    //Start it all off
    setTimeout(typeLetter, 500);
    #typing-area::after {
      content: '';
      display: inline-block;
      width: 0.1em;
      animation: blink 1s infinite;
    }
    
    @keyframes blink {
      50% {
        opacity: 0;
      }
    }
    <!DOCTYPE html>
    <html>
    
    <head>
      <title>Typing Example</title>
    
    </head>
    
    <body>
      <div id="typing-area"></div>
    
    </body>
    
    </html>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search