Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the last character keeps on printing repeatedly?

I have written the following to animate the text in a div, but I cannot find how does the last character gets printed repeatedly.

var textClass = $(".first-text");
var text = textClass.text();
textClass.text("");
for (var i in text) {
  $(textClass).animate({
    opacity: 0.25
  }, 200, function() {
    $(textClass).append(text.charAt(i));
  });
}
p:not(:first-child) {
  display: none;
}

p {
  margin: 0 auto;
  font-size: 24px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="animate-text">
  <p class="first-text">HTML</p><br>
</div>

If I try to the alert the value of i or text.charAt(i), I always get the desired output, but when I try to append the same in a div, I always get the same last letter that is printed repeatedly. I cannot find where I am mistaken. I cannot the find the bug in my logic.

If anyone could enlighten me on my mistake in the above code, I would be glad to hear it.

Here is the link to my fiddle where I tried this code.

Thanks in advance.

like image 960
Code_Ninja Avatar asked Dec 13 '22 15:12

Code_Ninja


1 Answers

You've stumbled into a bit of learning when it comes to closures. When i loops through, and eventually gets run inside the function, it's only looking at the last character, because that's what i was overwritten to before the first animate() actually fires.

You can counteract this by manually creating a closure yourself, wrapping it in a function and passing it in, to preserve the variable at the time of the loop.

For more information on closures, check out: What is a 'Closure'?

var textClass = $(".first-text");
var text = textClass.text();
textClass.text("");
for (var i in text) {
  (function (char) {
    $(textClass).animate({
      opacity: 0.25
    }, 200, function() {
      $(textClass).append(text.charAt(char));
    });
  })(i)
}
p:not(:first-child) {
  display: none;
}

p {
  margin: 0 auto;
  font-size: 24px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="animate-text">
  <p class="first-text">HTML</p><br>
</div>

Alternatively, you can use new let or const syntax, which defines i for the scope of the block (Which essentially creates a closure around your if block.)

var textClass = $(".first-text");
var text = textClass.text();
textClass.text("");
for (const i in text) {
  $(textClass).animate({
    opacity: 0.25
  }, 200, function() {
    $(textClass).append(text.charAt(i));
  });
}
p:not(:first-child) {
  display: none;
}

p {
  margin: 0 auto;
  font-size: 24px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="animate-text">
  <p class="first-text">HTML</p><br>
</div>
like image 99
ugh StackExchange Avatar answered Dec 17 '22 23:12

ugh StackExchange