Using setTimeout inside a for loop - not working - javascript

I have a setTimeout inside the a for loop, but it not behaving as i anticipated.
I have a bunch of banners in a page that are loading all at once. I am removing their parent's div html and storing it in an array. Then I would like for each parent to receive its corresponding html every 5 seconds. This only needs to happen once on ready state.
Here's my code...
function oneBanner() {
var divs = $('.banner-slide'),
imgs = [];
for ( var j = 0; j < divs.length; j++ ) {
imgs.push( $('.banner-slide:nth-child(' + (j+1) + ')') );
}
for ( var k = 0; k < imgs.length; k++ ) {
var url = $(imgs[k]).html();
$(imgs[k]).html('');
setTimeout(function(y) {
console.log(k * 5000);
$(imgs[k]).html(url);
}, k * 5000, k);
}
}
oneBanner();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div class="banner-slide">
<img src="http://www.placecage.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://fillmurray.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://stevensegallery.com/150/150" >
</div>
As you can see the images do not get printed on the screen one at a time every 5 seconds - which I thought I was doing.
Thank you for any help.
Serge

It will be better to simplify your code while you don't need any of variables/arrays outside this function .. you can just use jquery .each()
try This
function oneBanner() {
var divs = $('.banner-slide');
divs.each(function(i){ // loop through .banner-slide divs
var ThisIt = $(this); // define this outside setTimout function
setTimeout(function(){
divs.hide(); // hide all .banner-slide divs
ThisIt.show(); // show just this one
} , 5000 * i); // time * the i -- i is the index of the div
});
}
see the code in action
function oneBanner() {
var divs = $('.banner-slide');
divs.each(function(i){
var ThisIt = $(this);
setTimeout(function(){
divs.hide();
ThisIt.show();
} , 5000 * i);
});
}
oneBanner();
.banner-slide:not(:first){
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="banner-slide">
<img src="http://www.placecage.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://fillmurray.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://stevensegallery.com/150/150" >
</div>
Note: by using setTimeout() you'll show each image for 5 seconds and the code will stop looping
Update up to the OP comment
function oneBanner() {
var divs = $('.banner-slide'),
htmlArray = [];
divs.each(function(i){
var ThisIt = $(this); // get this outside the setTimout
htmlArray.push(ThisIt.html()); // push the inner html to the array
ThisIt.html(''); // emty this div
setTimeout(function(){
$(ThisIt).html(htmlArray[i]); // add html again with setTimeout every 5 second to its parent div
} , 5000 * i);
});
}
oneBanner();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="banner-slide">
<img src="http://www.placecage.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://fillmurray.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://stevensegallery.com/150/150" >
</div>

one word: closure
function oneBanner() {
var divs = $('.banner-slide'),
imgs = [];
for ( var j = 0; j < divs.length; j++ ) {
imgs.push( $('.banner-slide:nth-child(' + (j+1) + ')') );
}
imgs.forEach(($img,k)=>{
var url = $img.html();
$img.html('');
setTimeout(function(y) {
$img.html(url);
}, k * 5000, k);
})
}
oneBanner();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div class="banner-slide">
<img src="http://www.placecage.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://fillmurray.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://stevensegallery.com/150/150" >
</div>

You are referencing the wrong variable inside of your setTimeout. Replace 'y' with 'k'
function oneBanner() {
var divs = $('.banner-slide'),
imgs = [];
for ( var j = 0; j < divs.length; j++ ) {
imgs.push( $('.banner-slide:nth-child(' + (j+1) + ')') );
}
for ( var k = 0; k < imgs.length; k++ ) {
var url = $(imgs[k]).html();
$(imgs[k]).html('');
setTimeout(function(k) {
console.log(k * 5000);
$(imgs[k]).html(url);
}, k * 5000, k);
}
}
oneBanner();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div class="banner-slide">
<img src="http://www.placecage.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://fillmurray.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://stevensegallery.com/150/150" >
</div>

Related

Adding generated values from inputs

I have a site where I can enter the amount of an item, it will then take that input value and return the result on the page. I am then trying to get the results of all the items and return a grand total.
The issue is when I a loop to do this it will only add the first one.
I created a fiddle: https://jsfiddle.net/rc1mgLj5/4/
I am using querySelectorAll and using the length of all the classNames for the result of the first return.
Then looping them after parsing them to a number from text.
But at the moment it is only doing the first calculation. If I delete the for loop the first part works correctly again.
So since its only doing the first calculation for the first item, I get NaN for the second because it does not have a number to parse.
const total = document.querySelectorAll(".tot");
const price = document.querySelectorAll(".cost");
let textval = document.querySelectorAll(".qty-item");
const cal = document.getElementById("calc");
const errorMessage = document.querySelectorAll(".error");
cal.addEventListener("mouseover", function(e) {
console.log(total);
for (var i = 0; i < price.length; i++) {
let xPrice = price[i].innerHTML.split("$");
let parsePrice = parseFloat(xPrice[1]);
if (textval[i].value === "" || isNaN(textval[i].value)) {
setMessage("Please enter a number", "red");
} else {
let x = parseFloat(textval[i].value);
let y = parsePrice;
let z = x * y;
total[i].innerText = z.toFixed(2);
total[i].innerText = z;
for (i = 0; i < total.length; i++) {
let j = parseFloat(total[i].innerHTML);
console.log(j);
}
}
}
});
HTML:
<body>
<div class="main">
<span class="title">A Title</span>
</div>
<div class="content">
<div class="item">
<span>Item 1</span>
</div>
<div>
<span class="cost">$100.00</span>
</div>
<div id="qty">
<label>QTY:</label><input placeholder="0" class="qty-item">
<p class="error"></p>
</div>
<div class="tot">
<span><label>TOTAL</label> $0.0</span>
</div>
</div>
<br><br>
<div class="main">
<span class="title">A Title</span>
</div>
<div class="content">
<div class="item">
<span>Item 2</span>
</div>
<div>
<span class="cost">$50.00</span>
</div>
<div class="qty">
<label>QTY:</label><input placeholder="0" class="qty-item">
<p class="error"></p>
</div>
<div class="tot">
<span><label>TOTAL</label> $0.0</span>
</div>
</div>
<div class="calc-button">
<button id="calc">Calculate Prices</button>
</div>
</body>
You are nesting two fors using the same i variable as index:
cal.addEventListener('mouseover', function(e) {
console.log('total', total);
for (var i = 0; i < price.length; i++) {
//...
for (i = 0; i < total.length; i++) { // <== uses "i" again
let j = parseFloat(total[ii].innerHTML);
console.log(j);
}
}
}
});
Just replace that second for's variable with another name. Example:
for (let k = 0; k < total.length; k++) {
let j = parseFloat(total[k].innerHTML);
console.log(j);
}
Demo: https://jsfiddle.net/acdcjunior/gpLvszx3/
It seems you are using the same variable "i" for both loops and i is being reset in the second loop to 3 and hence the main loop runs only once. So i removed the following code and calculated the total outside main loop. seems to be working fine now. https://jsfiddle.net/uxr7ac9k/7/
total[i].innerText = z;
for (i=0;i < total.length; i++){
let j = parseFloat(total[i].innerHTML);
console.log(j);
}

Looping through the children of parent containers

I have 2 groups of parent containers, both with 5 children each -- 4 paragraphs and 2 buttons per container.
When the button in each container is clicked, a class is added to the paragraph element, one at a time. After the last paragraph child element is reached, the first paragraph child gets the class added to it again.
Below are the code. When the last paragraph is reached, I want the class added immediately to the first paragraph -- but the counter won't reset.
If you check the console.log, both counter and j go to 4, which it shouldnt. After both counter and j reaches 3, it should reset back to 0. My parameters are probably way off.
var container = document.querySelectorAll(".container");
var button = document.querySelectorAll("button");
var p = document.querySelectorAll("p");
var click = function(i) {
var counter = -1;
button[i].addEventListener("click", function() {
counter++;
console.log(counter);
for (j = 0; j < p.length / 2 + 1; j++) {
console.log(i, j);
this.parentNode.children[j].classList.remove("active");
if (j === counter) {
this.parentNode.children[j].classList.add("active");
}
if (counter === p.length / 2) {
counter = -1;
}
}
});
}
for (i = 0; i < button.length; i++) {
click(i);
}
.active {
background-color: red;
}
<div class="container">
<p>Test1</p>
<p>Test2</p>
<p>Test3</p>
<p>Test4</p>
<button>click</button>
</div>
<div class="container">
<p>Test1</p>
<p>Test2</p>
<p>Test3</p>
<p>Test4</p>
<button>click</button>
</div>
It's enough to add a modulus 4 op immediately after the increment:
counter %= 4;
Because the number of paragraphs may change you can compute their number on the fly:
var maxParagrapgh = button[i].parentNode.querySelectorAll('p').length;
And so the increment is:
counter = (counter + 1) % maxParagrapgh;
The running snippet:
window.addEventListener('DOMContentLoaded', function(e) {
var container = document.querySelectorAll(".container");
var button = document.querySelectorAll("button");
var p = document.querySelectorAll("p");
var click = function(i){
var counter = -1;
var maxParagrapgh = button[i].parentNode.querySelectorAll('p').length;
button[i].addEventListener("click", function(){
counter = (counter + 1) % maxParagrapgh;
// console.log(counter);
for(j=0;j<p.length/2+1;j++){
// console.log(i, j);
this.parentNode.children[j].classList.remove("active");
if(j === counter){
this.parentNode.children[j].classList.add("active");
}
if(counter === p.length/2){
counter = -1;
}
}
});
}
for(i=0;i<button.length;i++){
click(i);
}
})
.active {
background-color: red;
}
<div class="container">
<p>Test1</p>
<p>Test2</p>
<p>Test3</p>
<p>Test4</p>
<button>click</button>
</div>
<div class="container">
<p>Test1</p>
<p>Test2</p>
<p>Test3</p>
<p>Test4</p>
<button>click</button>
</div>

Changing the name of a html class with for loop variable

I have several of html class's incrementing up in class name such as:
<div class="chicken1">
<b></b>
</div>
<div class="chicken2">
<b></b>
</div>
<div class="chicken3">
<b></b>
</div>
I'm trying to write a for loop which will loop through these class names, adding the index to the end each class name and then calling a function in 2s delays.
for ( var i = 1; i <= 3; i++ ) {
setTimeout(function() {
myFunction(".chicken" + i + " b");
}, 2000 * i);
}
However this isn't working.
Fiddle
The problem is actually that of setTimeout() called within a loop; to do this properly you have to close over the loop variable:
for (var i = 1; i <= 6; ++i) {
setTimeout((function(i) {
return function() {
myFunction(".chicken" + i + " i");
};
})(i), i * 2000);
}
Demo
It uses a function that gets called immediately, passing the value of i; this value is retained until the setTimeout() is fired.
are you using jquery? try
for ( var i = 1; i <= 3; i++ ) {
myFunction($(".chicken" + i + " b"));
}
in jquery, to select elements,class etc. we need $("<selector here>");
This works fine for me:
<html>
<head>
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
</head>
<body>
<div class="chicken1">
<b></b>
</div>
<div class="chicken2">
<b></b>
</div>
<div class="chicken3">
<b></b>
</div>
<script>
$( document ).ready(function() {
for ( var i = 1; i <= 3; i++ ) {
$(".chicken"+i+" b").html("Hey " + i);
}
});
</script>
</body>
</html>

Can't get child div IDs within each parent div/class

When I try to get child div IDs within each parent div/class I get the error "Uncaught TypeError: Cannot set property '0' of undefined". I am using this javascript with scriptaculous so I have turned off the "$" shortcut.
Example HTML:
<div id="group1" class="section">
<h3 class="handle"><input type="hidden" name="groupName1" value="MyGroup1">MyGroup1</h3>
<div id="item_73548" class="lineitem">item a</div>
<div id="item_73386" class="lineitem">item b</div>
<div id="item_73163" class="lineitem">item c</div>
</div>
<div id="group2" class="section">
<h3 class="handle"><input type="hidden" name="groupName2" value="MyGroup2">MyGroup2</h3>
<div id="item_73548" class="lineitem">item d</div>
<div id="item_73386" class="lineitem">item e</div>
<div id="item_73163" class="lineitem">item f</div>
</div>
The Javascript:
$.noConflict();
var sections = document.getElementsByClassName('section');
var groups = new Array();
for (i = 0; i < sections.length; i++) {
var section = sections[i];
var sectionID = section.id;
var j = 0;
jQuery.each(jQuery("#" + sectionID + " .lineitem"), function () {
groups[i][j] = jQuery(this).attr('id');
j++;
});
}
console.log(groups);
The output should be:
groups[0][0]="item_73548";
groups[0][1]="item_73386";
groups[0][2]="item_73163";
groups[1][0]="item_73548";
groups[1][1]="item_73386";
groups[1][2]="item_73163";
Fiddle here: http://jsfiddle.net/qy9dB/3/
You just need to make sure that groups[i] is setup as an array before you try and add 2nd level elements to the array.
$.noConflict();
var sections = document.getElementsByClassName('section');
var groups = new Array();
for (i = 0; i < sections.length; i++) {
var section = sections[i];
var sectionID = section.id;
groups[i] = [];
var j = 0;
jQuery.each(jQuery("#" + sectionID + " .lineitem"), function () {
groups[i][j] = jQuery(this).attr('id');
j++;
});
}
console.log(groups);

Select top 3 values from variable, then next 3 etc

I have this variable with images. I also have 3 div's in which I want to put the images.
var images = [
'dali.jpg',
'illusionisme.png',
'impresionisme.jpg',
'popart.jpg',
'abstracter.jpg',
'abstrat.jpg',
'concept.jpg',
'fingerpaint.jpg',
'flowers.jpg',
'graffiti.jpg',
'groovy.jpg',
'skelly.jpg',
'vangogh.jpg'
]
By using this code every div does get a random image, which is nice but not what I want. How can I use jQuery to put the first 3 images inside the 3 divs, then the second 3 images in the div?
$(".art").click(function(){
$(".art").each(function(){
$(this).find("img").remove();
$(this).prepend('<img src="assets/images/' + images[Math.floor(Math.random()*images.length)] + '">');
});
});
<div class="art">
<div class="art">
<div class="art">
Not sure what you mean, please elaborate if this is not what you are looking for..
http://jsfiddle.net/jFIT/c7U7q/1/
where the code is giving just text now, you can wrap that text in an <img src= /> to give you the images..
var images = [
'dali.jpg',
'illusionisme.png',
'impresionisme.jpg',
'popart.jpg',
'abstracter.jpg',
'abstrat.jpg',
'concept.jpg',
'fingerpaint.jpg',
'flowers.jpg',
'graffiti.jpg',
'groovy.jpg',
'skelly.jpg',
'vangogh.jpg'];
$(".art").click(function () {
$(this).html(getNext3()); //images[Math.floor(Math.random()*images.length)]);
});
$('#startLoop').click(function () {
loopImages();
});
function loopImages(){
var art = $('.art');
art.fadeOut(1000, function () {
art.html(getNext3()).fadeIn(1000, function() { loopImages(); });
});
}
var counter = 0;
function getNext3() {
var imgs = "";
//img src=...
for (i = 0; i < 3; i++) {
imgs += ' ' + images[counter];
counter++;
}
return imgs;
}
UPDATED
(load 3 into 3 divs at a time.)
http://jsfiddle.net/jFIT/c7U7q/7/
function setNext3() {
var imgs = "";
//img src=...
for (i = 0; i < 3; i++) {
imgs = images[counter];
console.log(imgs);
console.log(i);
$("div.art:nth-child(" + (i + 1) + ")").html(imgs);
console.log($("div.art:nth-child(" + i + ")"));
counter++;
}
}
You can keep track of the current image index and then add the number to increase the index by each click
html
<div class="art">
<img data-imageindex="0" src="" />
</div>
<div class="art">
<img data-imageindex="1" src="" />
</div>
<div class="art">
<img data-imageindex="2" src="" />
</div>
js
var artLength = $(".art").length;
$(".art").click(function () {
$(".art").each(function () {
var $image = $(this).find("img");
var nextImageIndex = $image.data("imageindex") + artLength;
if (nextImageIndex >= images.length) {
nextImageIndex -= images.length;
}
$image.data("imageindex", nextImageIndex).attr("src",
"assets/images/" + images[nextImageIndex]);
});
});
http://jsfiddle.net/44zB4/

Categories

Resources