Home > Blockchain >  What changes will allow typewriter effect in JavaScript specific to my code?
What changes will allow typewriter effect in JavaScript specific to my code?

Time:08-24

I am a newbie to JavaScript and trying to make a portfolio for practice. On my portfolio I've been trying to add a typewriter effect on my 'About' section. The idea was to retrieve a String from an array called 'paragraphArray' and display it, one character at a time to a newly created paragraph element for each element in the array in a function which will, for testing purpose, write one character every 0.1 second. The code runs, however everything is printed all at once. Any guidance would be appreciated.

Here is my JS Code:

   let paragraphArray = [
    "Hi! My name is Zainal Shariff.",
    "I graduated from the University of the South Pacific with a bachelors degree, majoring on Computer Science and Information Systems.",
   ];

let aboutContainer = document.querySelector(".about-container");

document.addEventListener('DOMContentLoaded', typeWriter);

function typeWriter(event) {

    for (let i = 0; i < paragraphArray.length; i  ) {
        let interval1;

        let targetParagraph = paragraphArray[i];

        let newParagraph = document.createElement("p");
        newParagraph.innerHTML = "";
        aboutContainer.append(newParagraph)

        let j = 0;
        if (!interval1) {
            interval1 = setInterval(function () {

                while (j < targetParagraph.length) {
                    let character = targetParagraph[j];
                    printParagraphFromArray(newParagraph, character);
                    j  ;
                }

            }, 100);

        }

        aboutContainer.append(document.createElement("br"));

        if (i === paragraphArray.length1) {
            clearInterval(interval1);
            interval1 = null;
        }
    }
}

function printParagraphFromArray(newParagraph, target) {
    newParagraph.innerHTML = newParagraph.innerHTML   target;
}

CodePudding user response:

I would put the interval at the top layer of your code -- trying to run time-delayed intervals inside for loops can often result in very confusing code, like what you've written here. I rewrote your code to be a recursive function that just steps through each paragraph, and each character in each paragraph. This removes the confusion of a for loop spawning multiple simultaneous intervals -- the code executes relatively linearly, with only one timeout at a time.

let paragraphArray = [
  "Hi! My name is Zainal Shariff.",
  "I graduated from the University of the South Pacific with a bachelors degree, majoring on Computer Science and Information Systems.",
];

let aboutContainer = document.querySelector(".about-container");

document.addEventListener('DOMContentLoaded', startParagraph);

let curParagraphIndex = 0;
let curParagraphCharacterIndex = 0;
let curParagraphElement = null;
let curParagraphString = "";

function startParagraph(){
  //we're done
  if(curParagraphIndex > paragraphArray.length){
    return;
  }
  //otherwise start next paragraph
  let newParagraph = document.createElement("p");
  newParagraph.innerHTML = "";
  aboutContainer.append(newParagraph)
  curParagraphElement = newParagraph;
  curParagraphCharacterIndex = 0;
  curParagraphString = "";
  addCharacter();
}

function addCharacter(){
  //base case, we're done with this paragraph
  if(curParagraphCharacterIndex >= paragraphArray[curParagraphIndex].length){
    curParagraphIndex  ;
    startParagraph();
  }else{
    //add another character to this paragraph
    curParagraphString  = paragraphArray[curParagraphIndex][curParagraphCharacterIndex];
    curParagraphElement.innerText = curParagraphString;
    curParagraphCharacterIndex  ;
    setTimeout(addCharacter, 100);
  }
}
<div >
</div>

CodePudding user response:

It will be easier to make the asynchronous loop a function and have that function called with setTimeout as long as there are characters to display. Also try to minimize the number of global variables you have: the variables needed to manage the progress of the asynchronous loop should not have to be globals.

Here is a possible implementation:

const paragraphArray = [
    "Hi! My name is Zainal Shariff.",
    "I graduated from the University of the South Pacific with a bachelors degree, majoring on Computer Science and Information Systems.",
];

const aboutContainer = document.querySelector(".about-container");

document.addEventListener('DOMContentLoaded', typeWriter);

function typeWriter(paraElement, paraIndex=0, charIndex=0) {
    if (!charIndex) { // Starting a new paragraph
        if (paraIndex >= paragraphArray.length) return; // All done
        paraElement = document.createElement("p");
        aboutContainer.appendChild(paraElement);
    }
    paraElement.textContent = paragraphArray[paraIndex].slice(0, charIndex   1);
    // Prepare and schedule next run
    charIndex = (charIndex   1) % paragraphArray[paraIndex].length;
    setTimeout(() => typeWriter(paraElement, paraIndex   !charIndex, charIndex), 100);
}
<div ></div>

Note that the initial call to typeWriter will have the event object as first argument, but that argument is not used when the second argument is 0 -- which it is in that initial call.

  • Related