Experiencing difficulty creating a realistic typing effect with JavaScript that would accurately simulate typing errors

I condensed everything into a single HTML file for easier testing of this specific section.

The objective is to initially type Wx, then delete the x, pause for a second, and finally type elcome.

Currently, the output is Wlcome. I have attempted various methods but am unable to achieve typing the entire Welcome without missing the initial e.

Any assistance would be greatly appreciated.

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>

Answer №1

Make sure not to alter your currentIndex (= 2), simply include a flag indicating that you have already displayed an error message, allowing the next iteration to proceed normally:

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>

Answer №2

I have enhanced your code by implementing promises for better clarity

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>

Answer №3

If you've noticed the issue of always checking if the currentIndex === 1, then you're on the right track. The problem lies in constantly replacing the e with an x, causing it to repeat every time. Your solution of manually setting the index to 2 resulted in skipping the letter after the initial e. Remember, indexes start at 0!

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

By enforcing the index to be 2, you skipped past the letter following the first e.


To address this issue, I've implemented a form of "state tracking" using a boolean called hasTypedError. This ensures that the code branch typing the x only executes the first time. Additionally, the currentIndex++ has been moved outside the if statement to allow for incrementing in both scenarios. Moreover, the manual index reset in the removeX function has been fixed to reset to the correct index.

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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Ways to insert text at the start and end of JSON data in order to convert it into JSONP format

Currently, I am working on a project where I need to add a prefix "bio(" and a suffix ")" to my JSON data in order to make it callable as JSONP manually. I have around 200 files that require this modification, which is why I am looking for a programmatic ...

What is the technique for invoking methods of the Joi class without the need to instantiate an object?

I recently delved into using the Joi NPM module and found it confusing that although it is described as a class in the documentation, it does not require creating a class object like var joi = new Joi();. Can you explain how this works? My understanding o ...

Error message: NGINX combined with Express.js and socket.io, page not found

I currently have a node/express.js/socket.io application set up on an Ubuntu Server running on port 3002. I've made sure to open all ports on the machine for accessibility. When accessing the app directly at 11.111.111.1:3002/, everything runs smooth ...

How does React retain and display the previous values even after they have been updated?

https://codesandbox.io/s/objective-night-tln1w?file=/src/App.js After updating the data in the dropdown, the console displays the correct values. However, the dropdown itself continues to show the previous values. It seems that there may be an error relat ...

Exploring the differences between utilizing Node JS Express for server-side development and displaying console output to

Recently, I started delving into the world of node js and came across IBM's speech to text sample application (https://github.com/watson-developer-cloud/speech-to-text-nodejs). This app utilizes the express framework and showcases transcribed audio fr ...

Start the CSS3 animation in reverse right away

I am trying to achieve a "flashing" effect by adding the .shown class to my #overlay, causing the opacity to fade in for 2 seconds and then immediately reverse, fading out for another 2 seconds. After experimenting with removing the class, I found that it ...

Exploring nested maps in JavaScript

I attempted to nest a map within another map and encountered an issue where the innermost map is being executed multiple times due to the outer map. The goal is to link each description to a corresponding URL (using # as placeholders for some links). Here ...

Retrieve information from json, divide it, and transfer it to the chart for display

Greetings everyone! In my project, I am parsing a JSON file from an online API. However, I have encountered a roadblock while trying to split the data. Despite searching extensively on platforms like YouTube, I haven't been able to find a solution tha ...

Generating variable names dynamically in JavaScript

To prevent a javascript heap issue, I implement the usage of multiple arrays including 'family1', 'family2','family3' and 'dogs1', 'dogs2', 'dogs3'. For instance, you can use 'family1 and dog ...

validating if Object may be either 'null' or 'undefined'

In the code snippet below, I am attempting to verify whether hostel.country.address is null: return hostel.country.address && hostel.country.address.internalEmployeeIdentifier !== null || hostel.country.address.exter ...

Looping through color transitions upon hover using CSS

I am trying to create a color transition effect on hover, where the background changes from yellow to red and then back to yellow in a loop. I'm having trouble figuring out how to make this transition repeat continuously. Do I need to incorporate Java ...

Execute a function once all images have finished loading

My current approach involves utilizing a function to load images from an array: for (var i = 0; i < images_list.length; i++) { var img = new Image(); img.onload = function() { images_objects.push(this); ...

Oops! The angular app encountered an error: TypeError - it cannot read property '0' of undefined. Time to debug

Having difficulty grasping the source of an error, as the html side is able to read list[3].main.temp without any issues. However, in the second loop of the generateList function, I encounter an error specifically on $scope.list[i].main.temp, which throws: ...

Fill in the missing keys, values, and data within the JSON object

My JSON data consists of various objects with unique dates and site names. The dataset contains distinct dates such as: 2019-10-01, 2019-10-02, 2019-10-03, 2019-10-04, 2019-10-05. Some dates might be missing for certain sites in the dataset. For example, o ...

Organize the table data based on time

My website specializes in offering cell phone rental services. Users can visit the site to view the available devices that we have. I designed the display of these devices using a table format and components from "@mui/material". One of the columns in thi ...

Updating dropdown values using another dropdown through AJAX in Node.js: A step-by-step guide

My dilemma involves two dropdown menus: one for selecting the main category and another for choosing a subcategory. The goal is to dynamically populate the subcategory based on the main category selection. In my attempts so far, I have utilized JQUERY and ...

What is the reason why createServer() is often not recognized as a function?

After installing express globally and npm on my express app, I am encountering issues with both intellisence and the app itself (I am using visual studio code on mac OS Yosemite). Below is a snippet of the code: /// <reference path="typings/node/node. ...

What is the process for aligning rows with the selected option from the drop-down menu

Alright, so here's the scenario: I have created a table along with two drop-down filters. The first filter is for selecting the Year, and it offers options like "All", "2023", "2022", and "2021". When I pick a specific year, let's say "2022", onl ...

How can I prevent a browser from allowing users to select an image tag?

I'm dealing with an issue on my webpage where I have an image that is inadvertently picking up mouse clicks, causing the browser to perform drag and drop actions or highlight the image when clicked. I really need to use the mousedown event for somethi ...

Navigating through sibling elements can be accomplished by using various methods in

Can someone help me figure out how to assign unique IDs to 6 different Div elements as I step through them? The code snippet below is not working as expected, giving all Divs the same ID. What is the correct way to accomplish this task? $('#main-slid ...