Emel
Emel

Reputation: 2442

Function using setTimeout throws on subsequent calls

I'm trying something easy, a typewriting effect:

var i = 0;
var txt = "eco eco"
var speed = 1;
function typeWriter(idtxt) {
  if (i < txt.length) {
    document.getElementById(idtxt).innerHTML += txt.charAt(i);
    i++;
    setTimeout(typeWriter, speed);
  }
};
<button class="remo-btn" onclick="typeWriter('demo')">
<p id="demo"></p>

When I hardcode the id, the code works as intended:

document.getElementById("demo").innerHTML += txt.charAt(i);

But when I pass the id like this:

document.getElementById(idtxt).innerHTML += txt.charAt(i);

It only returns the first letter, in this case, "e" (from echo).

Can somebody help me?

Upvotes: 2

Views: 117

Answers (4)

Mister Jojo
Mister Jojo

Reputation: 22265

ES6 offer other way for that.

for example with Promise management:

const delay = ms => new Promise(r => setTimeout(r, ms))
  ,    txt  = 'Hello, world!'
  ;
async function typeWriter(idtxt)
  {
  const elm = document.getElementById(idtxt)
  for await (let letter of txt)
    {
    elm.textContent += letter
    await delay(500)
    }
  }
<button class="remo-btn" onclick="typeWriter('demo')">remo-btn</button>

<p id="demo"></p>

Upvotes: 2

Justin Taddei
Justin Taddei

Reputation: 2266

This is happening because the idtxt variable is out of scope after the first call to typeWriter. You can pass the parameter to subsequent calls to typeWriter by passing it as the first argument of setTimeout. Like so:

setTimeout(typeWriter, speed, idtxt);

You can read more about setTimeout here: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout

And you can learn more about why this is necessary here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures

var i = 0;
var txt = "eco eco"
var speed = 1000;
function typeWriter(idtxt) {
  if (i < txt.length) {
    document.getElementById(idtxt).innerHTML += txt.charAt(i);
    i++;
    setTimeout(typeWriter, speed, idtxt);
  }
};
<button class="remo-btn" onclick="typeWriter('demo')">
<p id="demo"></p>

Also, you probably meant for speed to equal 1000 (1 second). The delay of setTimeout is measured in milliseconds.

Upvotes: 3

Mister Jojo
Mister Jojo

Reputation: 22265

change setTimeout(typeWriter, speed ); to setTimeout(typeWriter, speed, idtxt );
you are missing to send idtxt argument

PS cahnge also var speed = 1000; 1s == 1000ms

var i = 0;
var txt = "eco eco"
var speed = 1000;
function typeWriter(idtxt) {
  if (i < txt.length) {
    document.getElementById(idtxt).innerHTML += txt.charAt(i);
    i++;
    setTimeout(typeWriter, speed, idtxt );
  }
};
<button class="remo-btn" onclick="typeWriter('demo')">
<p id="demo"></p>

Upvotes: 1

Hao Wu
Hao Wu

Reputation: 20669

You forgot to pass in idtxt while calling typeWriter in the setTimeout:

var i = 0;
var txt = "eco eco"
var speed = 1000;
function typeWriter(idtxt) {
  if (i < txt.length) {
    document.getElementById(idtxt).innerHTML += txt.charAt(i);
    i++;
    setTimeout(() => typeWriter(idtxt), speed);
  }
};
<button class="remo-btn" onclick="typeWriter('demo')">
<p id="demo"></p>

Upvotes: 3

Related Questions