jQuery each function parseInt loop - javascript

My code is supposed to make a set of divs with classes that start with status- fade out then change the classes from ie status-1 to status-11 by adding 10 the number. Everything is working except that the parseint is looping and the classes are becoming status-179831, status-179832...
$(function disappear(){
$('[class^="status-"]').delay(5000).fadeOut(400)
$('[class^="status-"]').each(function(){
num = $(this).attr('class').split('status-')[1];
num = parseInt(num, 10) + 10;
$(this).attr("class", "status-"+num+"");
})
$('[class^="status-"]').delay(1000).fadeIn(400)
disappear();
})

To get your operations to work in sequential order, you need to use the completion function of your animations like this:
$(function (){
function runOne(item) {
item.delay(5000).fadeOut(400, function() {
var num = item.attr('class').split('status-')[1];
num = parseInt(num, 10) + 10;
item.attr("class", "status-"+num+"")
.delay(1000).fadeIn(400, function() {runOne(item)});
});
}
// start all the animations
$('[class^="status-"]').each(function() {
runOne($(this));
});
})
Working demo: http://jsfiddle.net/jfriend00/k7aS7/
As your code was written, the two animations are asynchronous and your .each() loop or the next call to disappear() do not wait for the animations to finish. Using the completion functions like this triggers the next part of your sequence when the animation is done. You also want to always make sure you're using var in front of local variables to avoid accidentally making them global variables.
You can also synchronize a promise object which will guarantee that all the animations always start at the same time on each iteration:
$(function disappear() {
var all = $('[class^="status-"]');
all.delay(5000).fadeOut(400, function() {
var item = $(this);
var num = item.attr('class').split('status-')[1];
num = parseInt(num, 10) + 10;
item.attr("class", "status-"+num+"")
item.delay(1000).fadeIn(400);
})
// when all animations are done, start the whole process over again
all.promise().done(disappear);
})
Working demo of this option: http://jsfiddle.net/jfriend00/SY5wr/
To restore the class names to the original class name after each iteration, you could do this:
$(function () {
// save original class names
var all = $('[class^="status-"]').each(function() {
$(this).data("origClassName", this.className);
});
function disappear() {
all.delay(5000).fadeOut(400, function() {
var item = $(this);
var num = item.attr('class').split('status-')[1];
num = parseInt(num, 10) + 10;
item.attr("class", "status-"+num+"")
item.delay(1000).fadeIn(400);
})
// when all animations are done, start the whole process over again
all.promise().done(function() {
// restore class names
all.each(function() {
this.className = $(this).data("origClassName");
})
// run it all again
disappear();
});
}
// start it
disappear();
})
Working demo: http://jsfiddle.net/jfriend00/hTmHL/

Related

Loop a function while key is pressed

I'm trying to move a div up and down using two keys in Javascript. The idea is that while a certain key is depressed, a function loops and adds to the div's 'top' style value each time. The basic function works, but I can't get it to loop and I can't get anything to respond to a keypress.
It's hard to find info on keypress handling in Javascript, it seems most people use jQuery to handle that.
Is my use of the do-while loop correct? is there a better way to handle keydown and keyup events?
Here's my code:
var x = 0;
console.log(x);
function player1MoveDown() {
var value = document.getElementById("player1").style.top;
value = value.replace("%", "");
value = parseInt(value);
value = value + 1;
value = value + "%";
document.getElementById("player1").style.top = value;
console.log(value);
} //moves paddle down; adds to paddle's 'top' style value
function player1MoveSetting() {
x = 1;
do {
setInterval(player1MoveDown(), 3000);
}
while (x == 1);
console.log(x);
} //paddle moves while x=1; runs player1MoveDown function every 3 seconds
function player1Stop() {
x = 0;
}
And here's the relevant bit of HTML:
<div class="paddle" id="player1" style="top:1%" onkeydown="player1MoveSetting()" onkeyup="player1Stop()"></div>
You cannot attach a keydown event to a div, unless it has a tabindex:
<div class="paddle" id="player1"
onkeydown="player1MoveSetting()"
onkeyup="player1Stop()"
tabindex="1"
>
</div>
You can replace all this code:
var value = document.getElementById("player1").style.top;
value = value.replace("%", "");
value = parseInt(value);
value = value + 1;
value = value + "%";
document.getElementById("player1").style.top = value;
… with this:
var p1= document.getElementById('player1');
p1.style.top= parseInt(p1.style.top)+1+'%';
This calls the return result of player1MoveDown:
setInterval(player1MoveDown(), 3000);
Since player1MoveDown doesn't return anything, it's the equivalent of
setInterval(null, 3000);
To call the function every 3 seconds, do this instead:
setInterval(player1MoveDown, 3000);
This creates an infinite loop:
x = 1;
do {
setInterval(player1MoveDown, 3000);
}
while (x == 1);
Even though keyup will set the global x to 0, it will never run because the loop never ends.
Instead, create a timer variable, which is set on keydown and cleared on keyup.
Complete JavaScript Code
var timer;
function player1MoveDown() {
var p1= document.getElementById('player1');
p1.style.top= parseInt(p1.style.top)+1+'%';
console.log(p1.style.top);
}
function player1MoveSetting() {
if(timer) return;
timer= setInterval(player1MoveDown, 100);
}
function player1Stop() {
clearInterval(timer);
timer= null;
}
document.getElementById('player1').focus();
Working Fiddle

How to slow down a loop with setTimeout or setInterval

I have an array called RotatorNames. It contains random things but let's just say that it contains ["rotatorA","rotatorB","rotatorC"].
I want to loop through the array, and for each item i want to trigger a click event. I have got some of this working, except that the everything get's triggered instantly. How can i force the loop to wait a few seconds before it continues looping.
Here's what i have.
function Rotator() {
var RotatorNames = ["rotatorA","rotatorB","rotatorC"];
RotatorNames.forEach(function(entry){
window.setTimeout(function() {
//Trigger that elements button.
var elemntBtn = $('#btn_' + entry);
elemntBtn.trigger('click');
}, 5000);
});
}
You can run this to see what my issue is. http://jsfiddle.net/BxDtp/
Also, sometimes the alerts do A,C,B instead of A,B,C.
While I'm sure the other answers work, I would prefer using this setup:
function rotator(arr) {
var iterator = function (index) {
if (index >= arr.length) {
index = 0;
}
console.log(arr[index]);
setTimeout(function () {
iterator(++index);
}, 1500);
};
iterator(0);
};
rotator(["rotatorA", "rotatorB", "rotatorC"]);
DEMO: http://jsfiddle.net/BxDtp/4/
It just seems more logical to me than trying to get the iterations to line up correctly by passing the "correct" value to setTimeout.
This allows for the array to be continually iterated over, in order. If you want it to stop after going through it once, change index = 0; to return;.
You can increase the timeout based on the current index:
RotatorNames.forEach(function(entry, i) {
window.setTimeout(function() {
//Trigger that elements button.
var elemntBtn = $('#btn_' + entry);
elemntBtn.trigger('click');
}, 5000 + (i * 1000)); // wait for 5 seconds + 1 more per element
});
Try:
var idx = 0;
function Rotator() {
var RotatorNames = ["rotatorA", "rotatorB", "rotatorC"];
setTimeout(function () {
console.log(RotatorNames[idx]);
idx = (idx<RotatorNames.length-1) ? idx+1:idx=0;
Rotator();
}, 5000);
}
Rotator();
jsFiddle example
(note that I used console.log instead of alert)
Something like this should do what you're after:
function Rotator(index){
var RotatorNames = ["rotatorA","rotatorB","rotatorC"];
index = (index === undefined ? 0 : index);
var $btn = $("#btn_"+RotatorNames[index]);
$btn.click();
if(RotatorNames[index+1]!==undefined){
window.setTimeout(function(){
Rotator(index+1);
}, 500);
}
}

Loop through js array continually with pauses

I want to loop over an array continuously on click. Extra props if you can work in a delay between class switches :-)
I got this far:
// Define word
var text = "textthing";
// Define canvas
var canvas = 'section';
// Split word into parts
text.split();
// Loop over text
$(canvas).click(function() {
$.each(text, function(key, val) {
$(canvas).removeAttr('class').addClass(val);
});
});
Which is not too far at all :-)
Any tips?
The following will wait until you click the selected element(s) in the var el. In this example var el = $('section') will select all <section>...</section> elements in your document.
Then it will start cycling through the values in cssClassNames, using each, in turn as the css class name on the selected element(s). A delay of delayInMillis will be used between each class change.
var cssClassNames = ['c1', 'c2', 'c3'];
var el = $('section');
var delayInMillis = 1000;
// Loop over text
el.click(function() {
var i = 0;
function f() {
if( i >= cssClassNames.length ) {
i = 0;
}
var currentClass = cssClassNames[i];
i += 1;
el.removeClass().addClass(currentClass);
setTimeout(f, delayInMillis);
}
f();
});
I believe you want a delay of X milliseconds between removing a class and adding a class. I'm not sure that you have to have the lines marked // ? or even that they do the job, but what you do have to have is a way to get the value's into the function. Also, the setTimeout anon function might not actually need the parameters, but it should give you an idea.
$(canvas).click(function() {
$.each(text, function(key, val) {
$(canvas).removeAttr('class')
var $canvas = $(canvas) //?
var class_val = val //?
setTimeout(function ($canvas, class_val) {
$canvas.addClass(class_val);
}, 2000);
});
});
Edit: I'd do this instead
function modify_element($element, class_name){
$element.removeClass('class');
setTimeout(function ($element) {
$element.addClass(class_name);
}, 1000);
//adds the class 1 second after removing it
}
$(canvas).click(function() {
$.each(text, function(key, val) {
setTimeout(modify_element($(canvas), val),2000);
//this will loop over the elements with 2 seconds between elements
});
});
"loop over an array continuously" this sounds like a infinite loop, I don't think you want that. About pausing the loop, this is possible, you can use this

How do I build up my Javascript/Jquery for many elements using a loop?

instead of repeating the same code over and over again in my js file with the only difference being the element names, I was hoping to build a loop that would build out my js.
I'm tryign to add toggle functions to some buttons on my page that change their colors and sets a value elsewhere on my page. Here is my code:
var className;
var idName;
var i;
for (i = 0; i < 11; i++) {
className = ".feedbackq";
idName = "#feedbackq";
className = className + i.ToString();
idName = idName + i.ToString();
$(className).toggle(
function () {
$(className).each(function () {
$(className).css("background-color", "");
});
$(this).css("background-color", "red");
var value = $(this).val();
$(idName).val(value);
},
function () {
$(this).css("background-color", "");
$(idName).val("");
});
}
This is unfortunately not doing anything. When not in a loop, with hardcoded variable names, the code works, but I need this to be dynamic and constructed through a loop. The 11 count that is shown will eventually be a dynamic variable so I can't do hard coding....
Thanks for the help!
UPDATE: As requested, here is the not in the loop code:
$(".feedbackq0").toggle(
function () {
$(".feedbackq0").each(function () {
$(".feedbackq0").css("background-color", "");
});
$(this).css("background-color", "red");
var value = $(this).val();
$("#feedbackq0").val(value);
},
function () {
$(this).css("background-color", "");
$("#feedbackq0").val("");
});
$(".feedbackq1").toggle(
function () {
$(".feedbackq1").each(function () {
$(".feedbackq1").css("background-color", "");
});
$(this).css("background-color", "red");
var value = $(this).val();
$("#feedbackq1").val(value);
},
function () {
$(this).css("background-color", "");
$("#feedbackq1").val("");
});
$(".feedbackq2").toggle(
function () {
$(".feedbackq2").each(function () {
$(".feedbackq2").css("background-color", "");
});
$(this).css("background-color", "red");
var value = $(this).val();
$("#feedbackq2").val(value);
},
function () {
$(this).css("background-color", "");
$("#feedbackq2").val("");
});
One way to do this (without seeing your HTML for further simplifications) is to put the index number on the object before your event handlers using .data() so it can be retrieved later upon demand independent of the for loop index which will have run its course by then:
var className, idName, i;
for (i = 0; i < 11; i++) {
className = ".feedbackq" + i;
$(className).data("idval", i).toggle(
function () {
var idVal = $(this).data("idval");
$(".feedbckq" + idVal).css("background-color", "");
$(this).css("background-color", "red");
var value = $(this).val();
$("#feedbackq" + idVal).val(value);
},
function () {
var idVal = $(this).data("idval");
$(this).css("background-color", "");
$("#feedbackq" + idVal).val("");
});
}
Note: I've made a bunch of other simplifications too:
I declare multiple variables with one var statement.
toString(i) is not needed to add a number onto the end of a string and you had it mispelled too (with the wrong capitalization)
.each() is not needed to apply .css() to every item in a jQuery collection
I suspect that if we could see your HTML, we could significantly simplify this further as there are probably relationships between items that could be exploited to reduce code, but without the HTML we can't offer any advice on that.
You probably fell victim to the closures-inside-for-loops bug. You need the code inside the loop to be in a separate function, so each iteration gets its own className variables instead of them sharing the variables.
You could do this by crating a named function or by using a jQuery iterator function with a callback instead of a for loop
var toggle_stuff = function(i){
var className = ".feedbackq" + i; //The variables are local to just this iteration now
var idName = "#feedbackq" + i; //No need to call toString explicitly.
//And so on...
}
for(var i=0; i<11; i++){
toggle_stuff(i)
}
I kinda suspect that you are calling the wrong function, should be .toString() instead of .ToString().
Note that JavaScript is case-sensitive.
But if I write the code anyway I will ignore the .toString() part and use the numeric value directly...

jscript/jquery: fade in divs 1 by 1, with pause inbetween

I am totally stumped here.
I have a bunch of messages, each within a div "msg_feed_frame_$i" which increases, so message 1 is in div "msg_feed_frame_1", msg 2 is in "msg_feed_frame_2", etc etc. I want to fade these messages in one by one using jquery, but for some reason no matter what I do with settimeout and setinterval, the code immediately fades them all in simultaneously.
This is what i've got so far:
function feed(i)
{
var div = "#msg_feed_frame_";
var fader = div.concat(i);
$(fader).fadeIn(2000);
}
function timefade()
{
var num = 1;
for (num=1; num<=10; num++)
{
var t=setTimeout(feed(num),1000);
}
}
$(document).ready(function(){
timefade();
});
Your problem is that the for loop executes quickly and sets a timeout 1000ms from now for each function call. Here's one way you could remedy this:
function feed(i) {
var div = "#msg_feed_frame_";
var fader = div.concat(i);
$(fader).fadeIn(2000);
}
function timefade() {
var num = 1;
var fadeIt = function(i) {
return function() { feed(i); };
};
for (num = 1; num <= 4; num++) {
var t = setTimeout(fadeIt(num), num * 1000);
}
}
$(document).ready(function() {
timefade();
});
Additionally, your original code was passing setTimeout the results of the feed(i) function call (undefined), and it expects an object of type function. I added a helper function that returns a reference to a function that will call feed with the correct argument.
Capturing the value of num inside a function is called a closure, and it can be confusing at first. Check this post out for some good explanations of closures inside loops and while they're necessary.
Here's your example, working: http://jsfiddle.net/andrewwhitaker/tpGXt/
Try using jQuery's .delay() function...
function feed(i){
var div = "#msg_feed_frame_";
var fader = div.concat(i);
$(fader).fadeIn(2000).delay(1000);
}
function timefade(){
var num = 1;
for (num=1; num<=10; num++){
feed(num);
}
}
$(document).ready(function(){
timefade();
});

Categories

Resources