Reputation: 347
Hi I'm a newbie with JavaScript and Jquery. What I am trying to do here is to print the text passed in the onclick() function alphabet by alphabet using the setTimeout function. I'm not sure what i'm doing wrong. Thanks for your help.
HTML
<div>
<p id='myTxt'></p>
</div>
<input type='button' value='Submit' onclick="imScrolling('Hello World!!', 500, 0, document.getElementById('myTxt'))">
My Script.js file
function imScrolling(scrollTxt, interval, index, target)
{
//alert(scrollTxt + " " + interval + " " + scrollTxt.length + " " + index + " " + target.id);
while(index < scrollTxt.length)
{
//alert(scrollTxt[index]);
setTimeout(function (scrollTxt, interval, index, target)
{
$('#myTxt').append(scrollTxt[index]);
}, interval);
index++;
}
}
Also, I have noticed that if I do not pass the parameters to the setTimeout(), then the parameters like index, interval are shown as undefined in the alert message? Why is it so?
Upvotes: 0
Views: 506
Reputation: 138
Don't use setTimeout
. What you want is setInterval
.
function imScrolling(scrollTxt, interval, index, target) {
//alert(scrollTxt + " " + interval + " " + scrollTxt.length + " " + index + " " + target.id);
var notawhileloop = setInterval(function () {
//alert(scrollTxt[index]);
$('#myTxt').append(scrollTxt[index]);
index++;
if (index == scrollTxt.length) {
clearInterval(notawhileloop);
}
}, interval);
}
Working jsfiddle with your HTML.
Edit: Oops, forgot to stop the looping. Updated fiddle as well.
Edit 2: Found a neat trick that makes it easy to do this with setTimeout as well.
function imScrolling(scrollTxt, delay, index, target) {
while (index < scrollTxt.length) {
setTimeout(appendLetter, index * delay, scrollTxt, index);
index++;
}
}
function appendLetter(scrollTxt, index) {
$('#myTxt').append(scrollTxt[index]);
}
See it working in this fiddle. The trick is multiplying the delay
by index
(so first timeout is set at 0*500, second at 1*500, third at 2*500 etc). Hope this also demonstrates the passing of parameters.
Upvotes: 0
Reputation: 206151
function imScrolling(txt, intv, i, elID){
var $el = $(elID),
tot = txt.length,
interv = setInterval(doIt, intv);
function doIt(){
$el.append(txt[i++]);
if(i==tot) clearInterval(interv);
}
}
Now something interesting:
Instead of setInterval
, if you want to control the total time that occurs to do the animation you can use
.animate()
and it's step
function:
function imScrolling(txt, time, i, elID){
$({c:i}).animate(
{c:txt.length},{
duration : time,
easing : 'linear',
step : function(now){
d = ~~(now);
r = ~~(this.c);
if(d!==r)$(elID).append(txt[r]);
}
}
);
}
Upvotes: 0
Reputation: 3400
The problem is setTimeout
is asynchronous but your function keeps running the while
synchronously and so setTimeout
is being set many times immediately. This is what I suggest:
function imScrolling(scrollTxt, interval, index, target)
{
setTimeout(function (){
$('#myTxt').append(scrollTxt[index]);
if(index < scrollTxt.length){
imScrolling(scrollTxt, interval, index+1, target);
}
}, interval);
}
This way, you will set the interval again after the first one fires and not "at the same time". Demo
Upvotes: 1
Reputation: 27823
First of all let's start wth the function you call with setTimeout.
function (scrollTxt, interval, index, target) {
$('#myTxt').append(scrollTxt[index]);
}
You have defined a function with 4 parameters that gets called at a later time. The problem is that the function given to setTimeout isn't passed any parameters when it's called, so inside the anonymous function scrollTxt, interval, index and target will be undefined.
To get over this issue you can use a closure. Inside the anonymous function you can use variables available in the scope the anonymous function is defined:
var a = 5;
function () {
console.log(a); // 5
}
There is one more issue. The variables used are the actual variables, not copies. So if you change the variable outside, the value inside the anonymous function will change as well:
var a = 5;
var f = function () {
console.log(a);
}
a = 10;
f(); // outputs 10
The variable that changes for you is index. To get over that, you need to create a copy of it for each iteration. What better way to do that than to give it as parameter to a function?
for (var i=0; i<10; i++) {
setTimeout((function(new_i) {
return function () {
console.log(new_i);
};
})(i),100);
}
// outputs 0,1,2,3,4,5,6,7,8,9
Apply this and you can easily solve your problem (and understand how you're solving it).
Upvotes: 0
Reputation: 332
Try not use event attributes on HTML.
jQuery helps you with it.
Try:
HTML
<div id="container">
<p id="myTxt"></p>
<input type="button" value="Submit" id="your-button" />
</div>
JAVASCRIPT
$(function () // jquery dom ready
{
$("#container")
.on("click", "#your-button", function ()
{
var yourText = "Hello World!!".split('');
for (var i = 0; i < yourText.length; i++)
{
$("#myTxt")
.append(yourText[i])
.append("<br/>"); // just to line break
}
}
});
Working fiddle
Upvotes: 0