Neon Foxer
Neon Foxer

Reputation: 17

text.length is not defined in Javascript, but text is defined

I have a code that is supposed to show some text in a typewriter effect, but the console says that length is not defined. I do not know what to do, please help me.

function typeWriter(theX) {
  var i = 0;
  text = theX;
  var leng = text.length;
  if (i < leng) {
    document.getElementById("theTexts").innerHTML += text.charAt(i);
    setTimeout(typeWriter, speed);
  }
}
var speed = 50;
typeWriter('Frog-E Console');
var speed = 60;
typeWriter('Booting up');

Upvotes: 0

Views: 167

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1074839

Some issues:

  • When setTimeout calls your typeWriter function, it won't pass it a value for theX so you end up with theX being undefined, so text is undefined, so you get the error.
  • Your second typeWriter call won't wait until the previous one finishes before starting, so they'll stomp on each other. You can fix that by having typeWriter return a promise it fulfills when it's done.
  • Your text variable is undeclared, making it what I call an implicit global; we don't need that variable, so let's just ditch it.
  • Probably best to pass speed in rather than using a global.

Rather than having setTimeout call typeWriter directly, I'd probably use an inner function. See comments:

// Accept both text and speed
function typeWriter(text, speed) {
    // Return a promise we'll fulfill when done
    return new Promise(resolve => {
        // Start out showing nothing
        let currentLength = 0;

        // Start the process by showing the first character
        tick();

        function tick() {
            // Add one to what we're showing
            ++currentLength;
            // Show it
            document.getElementById("theTexts").innerHTML = text.substring(0, currentLength);
            // Done?
            if (currentLength === text.length) {
                // Yes, fulfill the promise
                resolve();
            } else {
                // No, keep going after a delay
                setTimeout(tick, speed);
            }
        }
    });
}

// Do the first one, wait for it to finish, then do the next
typeWriter("Frog-E Console", 50)
.then(() => {
    return typeWriter("Booting up", 60);
});
<div id="theTexts"></div>

Upvotes: 1

Jeremy Thille
Jeremy Thille

Reputation: 26390

By calling setTimeout(typeWriter, speed) you are calling typeWriter without passing it anything. This function expect one argument (a string), so you need to pass it :

function typeWriter(theX) {
  var i = 0;
  text = theX;
  var leng = text.length;
  if (i < leng) {
    document.getElementById("theTexts").innerHTML += text.charAt(i);
    setTimeout(typeWriter.bind(this, text), speed);
  }
}
var speed = 50;
typeWriter('Frog-E Console');
var speed = 60;
typeWriter('Booting up');
<div id="theTexts"></div>

However this doesn't produce the expected result, you should do something like this :

function typeWriter(text) {
  const char = text[0]
  theTexts.innerHTML += char;
  if (text.length > 1) setTimeout(typeWriter.bind(this, text.substring(1)), speed);
}

var speed = 50;
typeWriter('Frog-E Console');
<div id="theTexts"></div>

Upvotes: 1

Related Questions