I'm a beginner in JS, and I can't figure out what's wrong with my attempted slideshow. I understand this may seem like a repeat, and I've found a different, working way, to display a slideshow in JS, but I am simply confused about what is wrong with my code. Every single version of slideshow code I've seen sets all of the image urls in HTML and then hides them and only displays one of them using JS, but why wouldn't mine, with image urls simply set in an array, work?
<img id="sideimg" src="images/image1.jpg" alt="penguin" />
<script>
next();
var next=function(){
for(var i=0;i<3;i++){
var slide=document.getElementById("sideimg");
var slides=["images/image1.jpg","images/image2.jpg","images/image3.jpg"]
slide.src=slides[i];
timeOut();
if(i>=3){
i=0;
};
};
var timeOut=function(){
setTimeout(next,1000);
}
};
</script>
Order of functions is not right in your sample
You also need i to be defined outside the function and there is no need for the for loop
The following works for me in chrome
<img id="sideimg" src="images/image1.jpg" alt="penguin" />
<script>
var i = 0
var timeOut=function(){
setTimeout(next,1000);
}
var next=function(){
var slide=document.getElementById("sideimg");
var slides=["images/image1.jpg","images/image2.jpg","images/image3.jpg"]
slide.src=slides[i];
timeOut();
i++;
if(i>=3){
i=0;
};
};
next();
</script>
We could also define i within next as follows using IIFE (immediately invoked function expression). It is also better to declare slides and slide outside the function that is invoked every interval.
<img id="sideimg" src="images/image1.jpg" alt="penguin" />
<script>
var timeOut=function(){
setTimeout(next,1000);
}
var next=function(){
var i = 0;
var slides=["images/image1.jpg","images/image2.jpg","images/image3.jpg"];
var slide=document.getElementById("sideimg");
return function() {
slide.src=slides[i];
timeOut();
i++;
if(i>=3){
i=0;
};
};
}();
next();
</script>
Try moving the array OUTSIDE of the loop:
var next=function(slides){
var slide=document.getElementById("sideimg");
var slides=["images/image1.jpg","images/image2.jpg","images/image3.jpg"]
for(var i=0;i<3;i++){
slide.src=slides[i];
...
};
Here is another possibility (WARNING: I haven't actually tried it):
How do I add a delay in a JavaScript loop?
<img id="sideimg" src="images/image1.jpg" alt="penguin" />
<script type="text/javascript">
var slides=["images/image1.jpg","images/image2.jpg","images/image3.jpg"]
var slide=document.getElementById("sideimg");
var i = 0;
var loop = function () {
sideimg.src=slides[i]; // Display current image
i++;
if (i >= slides.length)
i = 0;
setTimeout(function () { // call setTimeout when the loop is called
loop(); // .. again which will trigger another
}, 1000)
};
};
</script>
};
Related
My code is running well...
but there is one thing I can't solve:
when I mouseover the image the loop starts well, but on subsequent mouseovers it starts changing faster and faster...
var Image = new Array("//placehold.it/400x180/?text=Welcome",
"//placehold.it/400x180/?text=To",
"//placehold.it/400x180/?text=My",
"//placehold.it/400x180/?text=Web+page",
"//placehold.it/400x180/?text=INPHP");
var Image_Number=0;
var Image_Length= Image.length;
function change_image(num){
Image_Number = Image_Number + num;
if(Image_Number > Image_Length)
Image_Number = 0;
if(Image_Number < Image_Length)
document.slideshow.src = Image[Image_Number];
return false;
Image_Number = Image_Length;
}
function auto () {
setInterval("change_image(1)", 1000);
}
<img src="//placehold.it/400x180/?text=Welcome" name="slideshow" onmouseover="auto()" />
On every mouseover you're reassigning a brand-new-interval™ resulting in multiple functions running at the same time.
name on IMG tag is an obsolete HTML5 attribute - See also img tag # W3.org
"change_image(1)" ...strings inside setInterval or setTimeout tigger eval. Which is bad. The real function name should be used instead: setInterval(functionName, ms)
You're not managing well the argument num
You cannot have code after a return statement
Use the mouseenter event (instead of mouseover)
and many more errors....
Here's a remake:
var images = [
"//placehold.it/400x180/?text=Welcome",
"//placehold.it/400x180/?text=To",
"//placehold.it/400x180/?text=My",
"//placehold.it/400x180/?text=Web+page",
"//placehold.it/400x180/?text=INPHP"
];
var c = 0; // c as Counter ya?
var tot = images.length;
var angryCat = false;
// Preload! Make sure all images are in tha house
for(var i=0; i<tot; i++) {
var im = new Image();
im.src= images[i];
}
function changeImage() {
document.slideshow.src = images[++c%tot];
}
function auto() {
if(angryCat) return; // No more mouse enter
angryCat = true;
setInterval(changeImage, 1000);
}
<img src="//placehold.it/400x180/?text=Welcome" name="slideshow" onmouseenter="auto()" />
The increment and loop is achieved using ++c % tot
The angryCat boolean flag helps to know it the auto() already started (mouse was there!), in that case it will return; (exit) the function preventing the creation of additional overlapping intervals on subsequent mouseenter (which was your main issue).
Additionally, I'd suggest to keep your JS away from HTML, so instead of the JS attribute event
onmouseenter="auto()"
assign an ID to your image id="myimage" and use JS:
document.getElementById("myimage").addEventListener("mouseenter", auto, false);
I am new to coding with js, and have tried many different ways to loop this code, as well as asking a friend of mine who is a bit more proficient than I am, and he was incorrect as well. I looked up how to use loops in js as well, and I seem to be stumped, so if you could also give me a basic explanation as to how loops in js work, that'd be great!
ORIGINAL CODE
function partA() {
var classes1 = document.getElementsByClassName('_jvpff _k2yal _csba8 _i46jh _nv5lf'); // finds follow button
var Rate1 = classes1[0];Rate1.click(); // clicks button1
}
setTimeout(partB, 20000); // begins func. B about 17 seconds after func a has been completed
function partB() {
var classes2 = document.getElementsByClassName('_de018 coreSpriteRightPaginationArrow'); // finds “next” arrow
var Rate2 = classes2[0];Rate2.click(); // clicks next arrow
}
partA(); // runs functions
The original code itself works fine, but it never seems to work with any loops I use.
Most Recent Loop Attempt
- Note: failed, obviously
function partA() {
var classes1 = document.getElementsByClassName('_jvpff _k2yal _csba8 _i46jh _nv5lf'); // finds follow button
var Rate1 = classes1[0];Rate1.click(); // clicks button1
}
setTimeout(partB, 20000); // begins func. B about 17 seconds after func a has been completed
function partB() {
var classes2 = document.getElementsByClassName('_de018 coreSpriteRightPaginationArrow'); // finds “next” arrow
var Rate2 = classes2[0];Rate2.click(); // clicks next arrow
}
partA(); // runs functions
for (i = 0; i < 30; i++) {
text += “The number is ” + i + “<br>”;
}
Thank you in advance!
- Michael
Any tips to just generally improve the code would also be appreciated.
Still can't work out exactly what you're after (looks like: trying to automate some repetitive task in some page for which you don't control the source)
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<title>JS Loop Example?</title>
<script>
function foo() {
var div = $("#x")[0];
div.innerHTML = "foo was clicked";
for (i = 0; i < 5; i++) {
div.innerHTML += "<br />!";
}
setTimeout(function(){ $('.barButton').click() }, 3000)
}
function bar() {
var div = $("#x")[0];
while (div.firstChild) {
div.removeChild(div.firstChild);
}
var wibble = document.createTextNode('bar was clicked');
div.appendChild(wibble);
for (i = 0; i < 5; i++) {
div.appendChild(document.createElement('br'));
wibble = document.createTextNode('?');
div.appendChild(wibble);
}
setTimeout(function(){ $('.fooButton').click() }, 3000)
}
</script>
</head>
<body onload='setTimeout(foo, 3000)'>
<script>
// Up until the close of the body, I can just write into the document.
document.write('<div id="x" class="stuffGoesHere">');
document.write('some random text<br />');
for (i = 0; i < 5; i++) {
document.write('#<br />');
}
document.write('</div>');
document.write('<input type="button" class="fooButton" value="foo" onClick="foo()" />');
document.write('<input type="button" class="barButton" value="bar" onClick="bar()" />');
</script>
</body>
</html>
FOr some reason my code is not executing properly. i am trying to program a slideshow with javascript. Im using a for loop to pull and populate the src files from a created array and change the pic every 3 seconds. THe page loads and the first pic is present but when the interval occurs the first pic dissapears and nothing falls in its place. What am I doing wrong?
<img name="mainSlide" id="mainSlide" src="images/mainPagePhotos/facebook-20131027-180258.png" alt="">
var mainSlidePics = ("facebook-20131027-180258.png","IMG_9694116683469.jpg","IMG_28452769990897.jpg");
window.onload = setInterval("mainSlide();", 3000);
function mainSlide() {
for(i=0; i<mainSlidePics.length; i++ ) {
document.images.mainSlide.src = "images/mainPagePhotos/" + mainSlidePics[i];
}
}
Have you tried getting the Id first?
var mainSlide = document.getElementById("mainSlide");
mainSlide.src = "images/mainPagePhotos/" + mainSlidePics[i];
also a forloop is a loop that finishes its loops even in one call.
try
var i = 0;
window.onload = setInterval("mainSlide(i);", 3000);
mainSlide(int j){
mainSlide.src = "images/mainPagePhotos/" + mainSlidePics[i];
setInterval("mainSlide(j++);", 3000);
}
First you have to correctly declare the array.
Then you have to move the counter variable outside the function triggered by setInterval.
Then pass the reference of the function to setInterval.
<img name="mainSlide" id="mainSlide" src="images/mainPagePhotos/facebook-20131027-180258.png" alt="">
<script type="text/javascript">
var mainSlidePics = ["facebook-20131027-180258.png","IMG_9694116683469.jpg","IMG_28452769990897.jpg"];
var position = 0;
function changePic() {
position = (position+1) % mainSlidePics.length;
document.images.mainSlide.src = "images/mainPagePhotos/" + mainSlidePics[position];
}
window.onload = function() {
setInterval(changePic, 3000);
};
</script>
Code below (the divs are shaded in my real example, I want to sequentially decrease their opacity to 0 so each disappears, in order.
I tried to doing this without using setTimeout, but all of the divs disappeared simultaneously - its good to know that the part of the code that changes the opacity works, but I cant seem to get them to work sequentially.
When I try to use setTimeout (which I presume I am implementing incorrectly),nothing happens!
Any help would be really appreciated with this, I'm fairly new to JavaScript and haven't touched it in a while and tutorials haven't been able to help me.
<body>
<div id="div1"></div>
<div id="div2"></div>
<div id="div3"></div>
<div id="div4"></div>
<script type="text/javascript">
// the divs that we want to cycle through are named here.
var divs = ["#div1", "#div2", "#div3", "#div4"];
var divsLength = divs.length;
for (var i = 0; i < divsLength; i++) {
setTimeout(function(){
$(divs[i]).fadeTo(1000, 0, function() {
});
},1500);
};
</script>
</body>
Here's a way you should be able to do this without setTimeout:
function doFade(items, index) {
$(items[index]).fadeTo(1000, 0, function() {
doFade(items, index + 1);
});
}
doFade(divs, 0);
If you're targetting browsers that support ES5 (most modern versions do), then you can further simplify doFade:
function doFade(items, index) {
$(items[index]).fadeTo(1000, 0, doFade.bind(this, items, index + 1));
}
working jsfiddle
You can use a recursive function to do that kind of thing, something like that :
function seqFade($el){
$el.first().fadeOut(500, function(){ //Take the first element and fade it out
seqFade($el.slice(1)); //Recall the function when complete with the same set of element minus the first one.
})
}
seqFade($('div')); //Call the function
http://jsfiddle.net/L2fvdfy2/
In your code, it could look like that :
function seqFade($el){
$el.first().fadeOut(500, function(){
seqFade($el.slice(1));
})
}
seqFade($('#div1, #div2, #div3, #div4'));
It's because when the timeout finally fires the variable "i" only has the last index value. Also the loop will start all the timeouts at almost the same time.
There are other ways to accomplish it but this might work with minimal changes to your code.
Try this:
<script type="text/javascript">
var divs = ["#div1", "#div2", "#div3", "#div4"];
var divsLength = divs.length;
for (var i = 0; i < divsLength; i++) {
setTimeout((function(index) {
return function(){
$(divs[index]).fadeTo(1000, 0, function() { });
}
)(i)),1500 + (i * 1500));
};
</script>
</body>
This will create an instance of the function with it's own copy of the index when it was called. Also increasing the timeout of each timeout will have them execute sequentially.
try this:
// the divs that we want to cycle through are named here.
var divs = ["#div1", "#div2", "#div3", "#div4"];
(function fade(i) {
$(divs[i]).fadeTo(1000, 0, function() {
setTimeout(function() {fade(++i);}, 500);
});
})(0);
for (var i = 1; i <= divsLength; i++) {
setTimeout(function(){
$(divs[i]).fadeTo(1000, 0, function() {
});
},1000*i);
lets try this
New to javascript and such, trying to create a loop for fading logos using jquery.
I've got it cycling through them just fine. But i tried to make the loop continuous; so that when it reached the last logo it went back to the beginning, by resetting my for-counter to 0 every time it reached the last logo. This resulted in an infinite loop i think that crashed my browser. So i did a quick google and discovered the window.setInterval(...) timer function.
My problem is, now that firing the looping code relies on timing, i can't figure out how to calculate the interval time. For reference here's the code that fades the logos in and out (before trying to loop it):
$(document).ready(function (){
var fadeDuration = 1000;
var timeBetweenFade = 2000;
var totalTimePerChange = fadeDuration + timeBetweenFade;
var totalLogos = $('.logo').length;
var currentLogo;
var i;
for(i = 0; i < totalLogos; i++)
{
currentLogo = "#img" + i;
if(i == 0){
$(currentLogo).fadeIn(fadeDuration).delay(timeBetweenFade).fadeOut(fadeDuration);
}
else{ //general case
$(currentLogo).delay(totalTimePerChange * i).fadeIn(fadeDuration).delay(timeBetweenFade).fadeOut(fadeDuration);
}
}
});
I tried to get the time a complete loop took in a couple of ways:
$(document).ready(function (){
//..declarations..
window.setInterval( function() {
//..FOR LOOP HERE..
}, i*(fadeDuration + timeBetweenFade + fadeDuration));
});
//I also tried..
$(document).ready(function (){
//..declarations..
var timeTakenToLoop;
var startLoopTime;
window.setInterval( function() {
startLoopTime = new Date().getTime();
//...FOR LOOP HERE..
timeTakenToLoop = new Date().getTime() - startLoopTime;
}, timeTakenToLoop);
});
But in both cases I get logos starting to overlap as the function calls timing is wrong. Could someone with a bit more experience suggest what the best approach would be?
Oh and just in case anyone needs it to understand the javascript, here's the html to match..
<div id="img0" class="logo">
<img src="{% static "CSS/Images/phone_icon.gif" %}"/>
</div>
<div id="img1" class="logo">
<img src="{% static "CSS/Images/email_icon.gif" %}"/>
</div>
<div id="img2" class="logo">I can fade too</div>
Simple jQuery approach, no setTimeout and no setInterval.
var loop = function(idx, totalLogos) {
var currentLogo = "#img" + idx;
$(currentLogo)
.delay(currentLogo)
.fadeIn(fadeDuration)
.delay(currentLogo)
.fadeOut(fadeDuration, function(){
loop( (idx + 1) % totalLogos, totalLogos);
});
}
loop(0, $('.logo').length);
See it here.