Reputation: 1877
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.
Upvotes: 4
Views: 125
Reputation: 22911
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>
Upvotes: 6
Reputation: 74
It seems to have a variable declaration in your script.
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));
});
}
Please review the following JSFiddle link. http://jsfiddle.net/tp3juw54/19/
Upvotes: 1
Reputation: 68923
You can either create a closure or use let
or const
to declare the variable i
inside for
loop which will preserve the current value of i
in each iteration:
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>
Upvotes: 2
Reputation: 178350
Using the let
and const
instead of var
you get a better scoping and do not need to create a closure. Also no need to keep doing $(textClass) - you can cache the object
const $textClass = $(".first-text");
const text = $textClass.text();
$textClass.text("");
for (let 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>
Upvotes: 1