Passing count variable in setInterval function - javascript

I am attempting to step through the array and every 3 seconds change the innerHTML of some items in the DOM. This code currently goes straight from 0(mixed media artist) to 2(descriptor) and doesn't display 1(art educator) at all. And the console.log outputs 0 1 2 for each setinterval loop.
Can anyone see what I am doing wrong to get this to work properly?
var heroItems = ['galleries', 'workshops', 'exhibitions'];
var heroBtns = ['view', 'sign UP', 'VIEW'];
var heroURLs = ['#', '#', '#'];
var descriptions = ['mixed media artist', 'art educator', 'descriptor'];
setInterval(function() {
for (var i = 0; i < descriptions.length; i++){
console.log(i)
changeDescription(i);
}
}, 3000);
function changeDescription(i) {
var descriptor = document.getElementById('descriptor').innerHTML = descriptions[i];
var hero = document.getElementById('hero').innerHTML = heroItems[i];
var heroRef = document.getElementById('heroref').setAttribute('href', heroURLs[i]);
var heroBtn = document.getElementById('herobtn').innerHTML = heroBtns[i];
}

The problem is, you don't wait after each loop iteration. You only wait once, after changing the description 3 times.
In your case, you could also totally skip the loop.
var i = 0;
var timer = window.setInterval(function() {
changeDescription(i);
if (++i == descriptions.length) {
window.clearInterval(timer);
}
}, 3000);

Related

How define a couple of setIntervals and clear them with delay

I need to randomly change characters of a text and after some delay fix them.
There is my code:
<h1 id="text" style="margin-top:100px;">SOME TEXT</h1>
<script>
var text = document.getElementById("text").innerHTML.split("");
var myArr = text;
for (i = 0; i < myArr.length; ++i) {
var handle = setInterval(function () { xyz(i) }, 100);
setTimeout(function (handle) {
myArr[i] = text[i];
clearInterval(handle);
}, (i) * 1000);
}
function xyz(index) {
myArr[index] = String.fromCharCode(Math.random() * 26 + 65);
document.getElementById("text").innerHTML = myArr;
}
</script>
It seems i have no a good understanding of how setInterval work! :(
EDIT:
With my code only text[text.length+1] character has change that mean passed parameter to xyx() function is last value of loop counter variable (after loop over). Now my question is how trigger setInterval() function with i = 0 ,1 ... , text.length.
Can someone guide me?
basicly setInterval execute a function with a iteration in time. and setInterval gives you a promise to cancel it any time you want.
var myPromise = setInterval(function(){
//some code here
},delayMiliseconds);
to cancel this code
clearInterval(myPromise);
Related to this question problem was wrong way to passing arguments to setInterval().the callback function i passed to setInterval() maintains a reference to "i" rather than the snapshot value of "i" as it existed during each particular iteration...
<h1 id="text" style="margin-top:100px;">SOME TEXT</h1>
<script>
var text = document.getElementById("text").innerHTML.split("");
var myArr = document.getElementById("text").innerHTML.split("");
for (i = 0; i < text.length; i++) {
var handle = setInterval(function (k) { xyz(k) }, 100,i);
setTimeout(function (handle, i) {
console.log(i);
console.log(text[i]);
myArr[i] = text[i];
clearInterval(handle);
}, (i) * 1000,handle,i);
}
function xyz(index) {
myArr[index] = String.fromCharCode(Math.random() * 26 + 65);
document.getElementById("text").innerHTML = myArr.toString();
}
</script>

JavaScript Variable in method modifying object's attribute?

I'm trying to create a poker game in JavaScript. I thought the function that tested flushes worked perfectly until I displayed the hand AFTER the method ran. If there is a flush, this function is supposed to show the user's full hand, and then only the flush underneath it. Instead, it shows only the flush, and then the flush again underneath it:
var $ = function (id) { return document.getElementById(id); };
var test = function() {
var deck = new POKER.Deck(); //creates deck
var hand = new POKER.Hand(); //creates hand
//----------------TEST HAND UNTIL FLUSH-----------------
while (hand.getValue() != POKER.HAND_TYPE.FLUSH) {
deck.refreshDeck(); //refresh deck with new cards
for (var i = 0; i < 7; ++i) { //populate hand
hand.addCard(deck.dealCard());
}
console.log(hand.size() + " before"); //only for debugging. Prints "7 before"
hand.testFlush();
console.log(hand.size() + " after"); //only for debugging. Result unexpected
if (hand.getValue() == POKER.HAND_TYPE.FLUSH) { //if hand has a flush
for (var j = 0; j < hand.size(); j++) { //display full hand
var img = document.createElement("img");
var card = hand.getCardAtIndex(j);
img.src = card.getImage();
$("images").appendChild(img);
}
for (var k = 0; k < 5; k++) { //display flush hand
var img2 = document.createElement("img");
var card2 = hand.getValueCardAtIndex(k);
img2.src = card2.getImage();
$("handImg").appendChild(img2);
}
break;
} else {
hand.empty();
}
}
};
window.onload = function() {
test();
};
The second console.log statement prints out "4 after" until the testFlush method detects a flush, and the final result is "5 after".
testFlush method:
POKER.Hand.prototype.testFlush = function() {
//first, sort cards by rank so that the highest flush is
//taken if there are more than five cards of the same suit
this.sortByRank();
this.sortBySuit();
var tempHand = this.cards; //modifiable version of this.cards
var NUM_OF_TESTS = 3; //only 3 loops required to test for all possible flushes
var LAST_CARD_INDEX = 4; //represents the fifth card, or index 4
var MAX_CARDS = 5; //maximum cards possible in a hand (valueCards)
for (var i = 1; i <= NUM_OF_TESTS; i++){
//check if 1st and 5th cards are the same suit
if(tempHand[0].getSuit() == tempHand[LAST_CARD_INDEX].getSuit()){
this.value = POKER.HAND_TYPE.FLUSH;
while(tempHand.length != MAX_CARDS){ //remove last card in tempHand until there are only five cards
tempHand.pop();
}
this.valueCards = tempHand;
}else{
tempHand.splice(0,1); //removes first card from the temporary hand
}
}
};
All "hand.size()" does in the test function is "return this.cards.length". So what I don't understand is how the testFlush method could be altering the object attribute "this.cards" when it only alters the temporary variable tempHand.
Hand object:
POKER.Hand = function(){
this.cards = [];
this.value; //integer that corresponds to the POKER.HAND_TYPE
this.valueCards = []; //array of the five cards that corresponds only to this.value
};
Hand.size method:
POKER.Hand.prototype.size = function() {
return this.cards.length;
};
The problem is this line:
var tempHand = this.cards; //modifiable version of this.cards
Assigning an array or object to a variable does not make a copy of it. The variable is a reference to the same array, so tempHand.pop() modifies this.cards as well. You can make a copy of an array with .slice():
var tempHand = this.cards.slice();

Looping through array of strings - stay on last string

I have this function which loops through a list of strings every 5 seconds. I would like it to stay on the last string after finishing the loop.
What do I need to change here?
window.specialWorkBoxStyleOverride = function(workBox) {
var statusTextBox = $("<div class = 'status-description-box'></div>");
$(workBox).append(statusTextBox);
var statusTexts = ["Checking", "Updating", "Processing", "Saving"];
var idx = 0;
var updateStatus = function() {
statusTextBox.text(statusTexts[idx]);
idx = (idx + 1) % statusTexts.length;
setTimeout(updateStatus, 5000);
};
updateStatus();
};
Thanks a lot.
Right now your code always calls setTimeout, so it will loop forever. Checking whether you've reached the end of your list should be sufficient to stop this (and means you don't need the modular arithmetic any more):
var updateStatus = function() {
statusTextBox.text(statusTexts[idx]);
idx++;
if (idx < statusTexts.length) {
setTimeout(updateStatus, 5000);
}
};

Constantly loop a javascript array and display results to div?

I have a bunch of testimonials for my site which are currently on a page and am trying to get a div to display each 1 at an interval of 5 seconds, if the array reaches the last value it should start back to beginning of the array again.
Here is what I have so far...
var testimonial = new Array();
testimonial[1] = "Rugby";
testimonial[2] = "Baseball";
testimonial[3] = "Cricket";
var length = testimonial.length
var i = 1;
setInterval(function() {
while (i <= length) {
$('#testimonials p').html(testimonial[i]);
++i;
if (i == length) {
i == 1;
}
}
}, 5000);
Any help would be great, thanks.
Try
var testimonial = ['Rugby', 'Baseball', 'Cricket'];
var numTestimonials = testimonial.length;
var index = 0;
setInterval(function() {
$('#testimonials p').text(testimonial[index]);
index = (index + 1) % numTestimonials;
}, 5000);
JavaScript arrays are 0-indexed and have handy array literal syntax. Using the modulus operator (%) is an idiomatic way of wrapping a counter back to 0 once it reaches a certain value.
You can try
setInterval(function() {
$('div').html(test[ (i = (i + 1) % length) ]) },
5000);
The function in setInterval is being called every 5 seconds. That means you display the 5 testimonials one after another really quick every 5 seconds instead of displaying them one after the other.
You should do something like:
var testimonial = new Array();
testimonial[1] = "Rugby";
testimonial[2] = "Baseball";
testimonial[3] = "Cricket";
var length = testimonial.length
var i = 0; // arrays start with 0
setInterval(function() {
$('#testimonials p').html(testimonial[i]);
i++;
if (i == length) i = 0;
}, 5000);
Many interesting answers, so one more won't hurt. :-)
You can bundle it all up in an immediately called function expression:
(function() {
var testimonials = ['Rugby', 'Baseball', 'Cricket'];
var i = 0;
setInterval(function() {
$('#testimonials p').text(testimonials[++i % testimonials.length]);
}, 5000);
}());

setTimeout inside for loop [duplicate]

This question already has answers here:
setTimeout in for-loop does not print consecutive values [duplicate]
(10 answers)
Closed 7 years ago.
I want a string to appear character-for-character with the following code:
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
for(c = 0; c < text.length; c++)
{
setTimeout('textScroller.innerHTML += text[c]', 1000);
}
}
window.onload = initText;
It's not working.. what am I doing wrong?
Try something like this:
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
var interval = setInterval(function() {
textScroller.innerHTML += text[c];
c++;
if(c >= text.length) clearInterval(interval);
}, 1000);
}
Note I added clearInterval to stop it when it's needed.
Currently, you are defining 18 timeouts and all will be executed ~ at once.
Second problem is, you pass instructions to execute as a String. In that case, the code won't have access to all variables defined in initText, because evaluated code will be executed in global scope.
IMO, this should do the job
function initText(){
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
(function(){
textScroller.innerHTML += text.charAt(c++);
if(text.length > c){
setTimeout(arguments.callee, 1000);
}
})();
}
Even more generic than answer by #yauhen-yakimovich:
Using Timeout:
var repeat = (function () {
return function repeat(cbWhileNotTrue, period) {
/// <summary>Continuously repeats callback after a period has passed, until the callback triggers a stop by returning true. Note each repetition only fires after the callback has completed. Identifier returned is an object, prematurely stop like `timer = repeat(...); clearTimeout(timer.t);`</summary>
var timer = {}, fn = function () {
if (true === cbWhileNotTrue()) {
return clearTimeout(timer.t); // no more repeat
}
timer.t = setTimeout(fn, period || 1000);
};
fn(); // engage
return timer; // and expose stopper object
};
})();
Using Interval:
var loop = (function () {
return function loop(cbWhileNotTrue, period) {
/// <summary>Continuously performs a callback once every period, until the callback triggers a stop by returning true. Note that regardless of how long the callback takes, it will be triggered once per period.</summary>
var timer = setInterval(function () {
if (true === cbWhileNotTrue()) clearInterval(timer);
}, period || 1000);
return timer; // expose stopper
};
})();
Slight difference between the two indicated in comments -- the repeat method only repeats after the callback performs, so if you have a "slow" callback it won't run every delay ms, but repeats after every delay between executions, whereas the loop method will fire the callback every delay ms. To prematurely stop, repeat uses an object as the returned identifier, so use clearTimeout(timer.t) instead.
Usage:
Just like answer by #soufiane-hassou:
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
var interval = repeat/* or loop */(function() {
textScroller.innerHTML += text[c];
c++;
return (c >= text.length);
}, 1000);
As mentioned, premature stopping would be:
/* if repeat */ clearTimeout(interval.t);
/* if loop */ clearInterval(interval);
Try this:
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
for(c = 0; c < text.length; c++)
{
setTimeout("textScroller.innerHTML += '" + text[c] + "'", 1000 + c*200);
}
}
window.onload = initText;
Try using a closure:
function init() {
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
function run() {
textScroller.innerHTML += text[c++];
if (c<text.length)
setTimeout(run, 1000);
}
setTimeout(run, 1000);
}
init()
The problem in your code is that the code you put in the string will run in the global context, where textScroller is not defined (it is defined inside your function).
I want to share a snippet (based on answer by Soufiane Hassou). It extends to the case when you literally replace a for-loop body to be iterated over some array in a fixed interval of time. Basically same synchronous loop but with "sleep" pausing (because javascript is not a synchronous programming language).
function loop(arr, take, period) {
period = period || 1000;
var i = 0;
var interval = setInterval(function() {
take(i, arr[i]);
if (++i >= arr.length) { clearInterval(interval);}
}, period);
}
Usage example:
loop([1, 2, 3, 4], function(index, elem){
console.log('arr[' + index + ']: ' + elem);
});
Tested in Node JS. Hope that helps someone.
edit>
the following update makes code usable together with libs doing heavy "prototyping" (like jQuery or prototype):
function loop(arr, take, period) {
period = period || 1000;
var scope = {
i: 0,
arr: arr,
take: take,
};
var iterate = (function iterate() {
if (this.i >= this.arr.length) { clearInterval(this.interval); return}
take(this.i, this.arr[this.i++]);
}).bind(scope);
scope.interval = setInterval(iterate, period);
}
Your for loop is setting a timeout for every character at once, so they will not appear in sequence, but all at once. Your setTimeout should include code to another setTimeout that will include the next character to display.
So something like this (didn't test this)
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
setTimeout('nextChar(text)', 1000);
}
function nextChar(text){
if(text.length > 0){
textScroller.innerHTML += text[0];
setTimeout('nextChar(text.substring(1))', 1000);
}
}
If you want to preserve setTimeOut (instead of setInterval) and use named function (instead of evaluating code block in setTimeOut call), then this could be helpful:
var b = {
textScroller: document.getElementById('textScroller'),
text: "Hello how are you?"
};
function initText() {
for(c = 0; c < b.text.length; c++) {
setTimeout("append("+c+")", 1000 + c*200);
}
}
function append(c) {
b.textScroller.innerHTML += b.text[c];
}
window.onload = initText;
With the above you can pass a parameter to append function.
To pass several parameters the next code does the trick:
var glo = [];
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = "Hello how are you?";
var timeout_time;
for(c = 0; c < text.length; c++) {
glo[glo.length] = {text:text, c:c, textScroller:textScroller};
timeout_time = 1000 + c * 200;
setTimeout("append(" + (glo.length - 1) + ")", timeout_time);
}
}
function append(i)
{
var obj = glo[i];
obj.textScroller.innerHTML += obj.text[obj.c];
obj = null;
glo[i] = null;
}
window.onload = initText;
With the above you have only one global array glo. In loop you create new array members to glo and in append() function refer to these members using index which is passed as parameter.
CAUTION: the second code sample is not meant as best or most suitable solution to OP:s problem, but may benefit in other setTimeOut relative problems, eg. when someone wants to make a presentation or performance test where some functionalities are needed to call after some delay. The advantage of this code is to make use of for loops (many coders want to use for loops) and the possibility to use also inner loops and the ability to "send" local variables in their loop time state to timeOut functions.
May be better to loop in cascade. For exemple to fade a div :
div=document.createElement('div');
div.style.opacity=1;
setTimeout(function(){fade(1);},3000);
function fade(op){
op-=.05;
if(op>0) setTimeout(function(){div.style.opacity=op;fade(op);},30);
else document.body.removeChild(div);
}

Categories

Resources