JSFiddle: http://jsfiddle.net/KH8Gf/27/
Code:
$(document).ready(function()
{
$('#expand').click(function()
{
var qty= $('#qty').val();
for (var counter = 0; counter < qty; counter++)
{
$('#child').html($('#child').html() + '<br/>new text');
}
});
});
How can I delay each iteration of the loop by a certain time?
I tried the following unsuccessfully:
setTimeout(function(){
$('#child').html($('#child').html() + '<br/>new text');
},500);
and
$('#child').delay(500).html($('#child').html() + '<br/>new text');
These cases all seem to work best by putting the operation into a local function and then calling that local function from setTimeout() to implement your delay. Due to the wonders of closures in javascript, the local function gets access to all the variables at the levels above it so you can keep track of your loop count there like this:
$(document).ready(function() {
$('#expand').click(function() {
var qty = $('#qty').val();
var counter = 0;
var child = $('#child');
function next() {
if (counter++ < qty) {
child.append('<br/>new text');
setTimeout(next, 500);
}
}
next();
});
});
Related
I'm making a simple program which increases a number incrementally for every 0.5 second. When I click start it works perfectly. But when I click restart, the increments go fine, but they don't increment every 0.5 sec and go pretty fast, and this happens when I am calling the same function? JS fiddle link below.
function runFunc(){
declare a variable interval outside function
var myInterval = null;
check if an interval is already running if yes clear it in order to avoid multiple interval running the same function which makes the interval became looks faster than the first time it's called
if (myInterval != null) {
clearInterval(myInterval);
}
also this is not correct
clearInterval(varName);
the parameter should be an interval which is like this
clearInterval(myInterval);
so your javascript code would be like this
var myInterval = null;
function runFunc(){
$('#counter').val(zero);
var varName = function(){
var number = Number($('#number').val());
var counter = Number($('#counter').val());
if(counter < number) {
counter++;
console.log(counter);
$('#counter').val(counter);
} else {
clearInterval(myInterval);
}
};
//check if an interval is already running if yes clear it
if (myInterval != null) {
clearInterval(myInterval);
}
myInterval = setInterval(varName, 500);
};
show.click(runFunc);
reset.click(function(){
$('#number').val(zero);
$('#counter').val(zero);
});
restart.click(runFunc);
u have to Declare a Variable for setInterval like "setIntervalID"
so stop it clearInterval("setIntervalID");
JSFIDDLE
var initialNumber = 10;
var zero = 0;
$('#number').val(initialNumber);
$('#counter').val(zero);
var show = $('#show');
var reset = $('#reset');
var restart = $('#restart');
var setIntervalID;
// console.log('initial value of number is ' + number);
// console.log(typeof number);
// console.log('initial value of counter is ' + counter);
var varName = function(){
var number = Number($('#number').val());
var counter = Number($('#counter').val());
if(counter < number) {
counter++;
console.log(counter);
$('#counter').val(counter);
}
}
function runFunc(){
$('#counter').val(zero);
setIntervalID = setInterval(varName, 500);
};
function stopFunc(){
clearInterval(setIntervalID);
};
function restartGO(){
stopFunc();
runFunc();
}
show.click(runFunc);
restart.click(restartGO);
reset.click(function(){
$('#number').val(zero);
$('#counter').val(zero);
});
I am making a typing game using just jQuery and javascript. It worked fine as a single player game, feel free to play it at http://typetothestars.bitballoon.com/ However, I am planning to keep ratcheting up its complexity level. So I am trying to add muti player to it now.
here it is in jsfiddle minus images https://jsfiddle.net/u32s4yty/
My problem lies in my runRace functions. I was expecting the race to run for player 1, when the interval ended, it would then start again for player 2. Instead, it runs through all the iterations right away. So apperently setTimeout is not going to work here.
Any suggestions as to how to make it work?
Thanks!
// ** RUNNING GAME FUNCTIONS ** \\
//hides instructions and reveals game
function setupRace(i) {
console.log("In Race Setup")
$("#word").show();
document.getElementById("word").focus();
generateWords();
$(".toType").text(gameWords[0]);
$("#instructions").hide();
$(".wordDisplay").show();
$(".player").show();
var playerAvatar = 'url("images/' + playerInfo[i].avatar + '.png")'
$(".player").css({background: playerAvatar});
}
//game timer - IS NOT STOPPING THE OTHER FUNCTIONS FROM RUNNING
var timeoutID;
function timer(i) {
timeoutID = window.setTimeout(checkEndRace, 3000, i)
console.log("i = " + i);
console.log(playerInfo[i]);
}
function checkEndRace(i) {
console.log("in check end race - num players " + numPlayers);
if (i < numPlayers - 1) {
setupRace(i);
}else {
endRace(i);
}
}
//advances ship on correct typing
function runRace() {
console.log("In run race");
var i = 0;
while (i < playerInfo.length) {
console.log("in run race loop");
setupRace(i);
timer(i);
//timer is skipping ahead to the next iteration, eventhough
//checkEndRace hasn't run yet
var j = 1;
$(document).keyup(function(e){
var targetWord = $(".toType").text();
var typedWord = $("#word").val();
while (j < gameWords.length){
if(typedWord === targetWord){
$(".player").css({left: "+=15px",});
targetWord = $(".toType").text(gameWords[j]);
$("#word").val("");
j++;
}else {
return
};
}
});
i ++;
};
}
I was hoping to use setTimeout to stop all functions the following functions, until the interval is completed.
Calls to setTimeout return immediately and only execute once so one easy/common way to handle ordering them is to make tail calls (tick) to setTimeout and to put all requests in a queue.
// ** RUNNING GAME FUNCTIONS ** \\
var raceHandlers = [];
var raceTimout = 3000;
function tick() {
// Tail call
if (raceHandlers.length > 0) {
var action = raceHandlers.pop();
setTimeout(action[0],raceTimeout,action[1]);
}
}
//hides instructions and reveals game
function setupRace(i) {
console.log("In Race Setup")
$("#word").show();
document.getElementById("word").focus();
generateWords();
$(".toType").text(gameWords[0]);
$("#instructions").hide();
$(".wordDisplay").show();
$(".player").show();
var playerAvatar = 'url("images/' + playerInfo[i].avatar + '.png")'
$(".player").css({background: playerAvatar});
tick();
}
//advances ship on correct typing
function runRace() {
console.log("In run race");
var i = 0;
while (i < playerInfo.length) {
console.log("in run race loop");
//setupRace(i);
raceHandlers.unshift([setupRace,i]);
//timer is skipping ahead to the next iteration, eventhough
//checkEndRace hasn't run yet
var j = 1;
$(document).keyup(function(e){
var targetWord = $(".toType").text();
var typedWord = $("#word").val();
while (j < gameWords.length){
if(typedWord === targetWord){
$(".player").css({left: "+=15px",});
targetWord = $(".toType").text(gameWords[j]);
$("#word").val("");
j++;
}else {
return
};
}
});
i ++;
};
raceHandlers.unshift([endRace,playerInfo.length]);
tick();
}
I want to make a delay inside my for loop, but it won't really work.
I've already tried my ways that are on stackoverflow, but just none of them work for what I want.
This is what I've got right now:
var iframeTimeout;
var _length = $scope.iframes.src.length;
for (var i = 0; i < _length; i++) {
// create a closure to preserve the value of "i"
(function (i) {
$scope.iframeVideo = false;
$scope.iframes.current = $scope.iframes.src[i];
$timeout(function () {
if ((i + 1) == $scope.iframes.src.length) {
$interval.cancel(iframeInterval);
/*Change to the right animation class*/
$rootScope.classess = {
pageClass: 'nextSlide'
}
currentId++;
/*More information about resetLoop at the function itself*/
resetLoop();
} else {
i++;
$scope.iframes.current = $scope.iframes.src[i];
}
}, $scope.iframes.durationValue[i]);
}(i));
}
alert("done");
This is what I want:
First of all I got an object that holds src, duration and durationValue.
I want to play both video's that I have in my object.
I check how many video's I've got
I make iframeVideo visible (ngHide)
I insert the right <iframe> tag into my div container
It starts the $timeout with the right duration value
If that's done, do the same if there is another video. When it was the last video it should fire some code.
I hope it's all clear.
I've also tried this:
var iframeInterval;
var i = 0;
$scope.iframeVideo = false;
$scope.iframes.current = $scope.iframes.src[i];
iframeInterval = $interval(function () {
if ((i + 1) == $scope.iframes.src.length) {
$interval.cancel(iframeInterval);
/*Change to the right animation class*/
$rootScope.classess = {
pageClass: 'nextSlide'
}
currentId++;
/*More information about resetLoop at the function itself*/
resetLoop();
} else {
i++;
$scope.iframes.current = $scope.iframes.src[i];
}
}, $scope.iframes.durationValue[i])
Each $timeout returns a different promise. To properly cancel them, you need to save everyone of them.
This example schedules several subsequent actions starting at time zero.
var vm = $scope;
vm.playList = []
vm.playList.push({name:"video1", duration:1200});
vm.playList.push({name:"video2", duration:1300});
vm.playList.push({name:"video3", duration:1400});
vm.playList.push({name:"video4", duration:1500});
vm.watchingList=[];
var timeoutPromiseList = [];
vm.isPlaying = false;
vm.start = function() {
console.log("start");
//ignore if already playing
if (vm.isPlaying) return;
//otherwise
vm.isPlaying = true;
var time = 0;
for (var i = 0; i < vm.playList.length; i++) {
//IIFE closure
(function (i,time) {
console.log(time);
var item = vm.playList[i];
var p = $timeout(function(){playItem(item)}, time);
//push each promise to list
timeoutPromiseList.push(p);
})(i,time);
time += vm.playList[i].duration;
}
console.log(time);
var lastPromise = $timeout(function(){vm.stop()}, time);
//push last promise
timeoutPromiseList.push(lastPromise);
};
Then to stop, cancel all of the $timeout promises.
vm.stop = function() {
console.log("stop");
for (i=0; i<timeoutPromiseList.length; i++) {
$timeout.cancel(timeoutPromiseList[i]);
}
timeoutPromiseList = [];
vm.isPlaying = false;
};
The DEMO on PLNKR.
$timeout returns promise. You can built a recursive chain of promises like this, so every next video will play after a small amount of time.
Just out of curiosity: can I reference a setInterval() id from itself, without having to store itself in a variable?
So, instead of doing this:
function counter() {
console.log(id + ": " + count++);
if (count > 10)
clearInterval(id);
}
var count = 0;
var id = setInterval(counter, 250);
I'd be doing this:
function counter() {
console.log(aReferenceToItsOwnId + ": " + count++);
if (count > 10)
clearInterval(aReferenceToItsOwnId);
}
var count = 0;
setInterval(counter, 250);
Which would, just in example, allow me to reuse the function simply, like this:
setInterval(counter, 200);
setInterval(counter, 250);
setInterval(counter, 333);
No, you can't. The only place accessible to your code that the id is tracked is the return value of the setInterval function.
If you want to reuse the function, you could wrap it like:
function startCounter(time) {
function counter() { ... }
var count = 0;
var id = setInterval(counter, time);
}
startCounter(200);
startCounter(250);
startCounter(333);
Use additional parameter of function to do this.
var si1=setInterval(function(){counter(1);},200);
var si2=setInterval(function(){counter(2);},250);
var si3=setInterval(function(){counter(3);},333);
function counter(id)
{
...
clearInterval(window['si'+id]);
...
}
As the other answers state, it is impossible. However, you could create a helper function to greatly ease that fact.
Code
function timer(callback, interval) {
var id = setInterval(function() {
callback.call({ id: id });
}, interval);
};
Usage
var count = 0;
function counter() {
console.log(this.id + ' - ' + count++);
if (count > 10) clearInterval(this.id);
};
timer(counter, 250);
timer(counter, 300);
I've got this code and I don't know why all the functions in the loop are called at once!
this.line = function($l) {
var $this = this;
$this.$len = 0;
$('.active').hide(0,function(){
$this.$len = $l.length;
var j = 1;
$.each($l,function(i,item){
var t = setTimeout(function(){
$this._echoLine($l[i]);
clearTimeout(t);
if (j >= $this.$len) $('.active').show();
j++;
},500*j);
});
});
}
It's because you only increment j inside the timeout function, but the delay (which depends on j) is still 1 at the time the timeout handler is registered.
Seeing as you have a loop index variable anyway (i), try this:
$l.each(function(i, item) {
setTimeout(function() {
$this._echoLine($l[i]);
}, 500 * (i + 1));
});
// a separate timeout to fire after all the other ones
setTimeout(function() {
$('.active').show();
}, ($l.length + 1) * 500);
There's no need for the clearTimeout line, so no need to declare or store t either.
Hope it works.
this.line = function($l) {
var $this = this;
$this.$len = 0;
$('.active').hide(0,function(){
$this.$len = $l.length;
var j = 1;
$.each($l,function(i,item){
var t = setTimeout(function(){
$this._echoLine($l[i]);
clearTimeout(t);
if (j >= $this.$len) $('.active').show();
j++;
});
});
});
}
setTimeout(function() { this.line(); }, 500);