Click event on a slider goes at the end of the array - javascript

I am trying to create a simple slider using javascript.
So far, here is my code :
html:
<div class="carousel-container">
<div class="slides-container">
<div class="slide">
<img src="assets/images/image-1.jpg" alt="">
</div>
<div class="slide">
<img src="assets/images/image-3.jpg" alt="">
</div>
<div class="slide">
<img src="assets/images/image-2.jpg" alt="">
</div>
<div class="slide">
<img src="assets/images/image-3.jpg" alt="">
</div>
</div>
</div>
<div class="carousel-nav">
<button class="button-previous">Previous</button>
<button class="button-next">Next</button>
</div>
Js :
const slides = document.querySelectorAll('.slide')
const slidesContainer = document.querySelector('.slides-container')
const slidesCount = slides.length
const slideWidth = slides[0].clientWidth
const prevButton = document.querySelector('.button-previous')
const nextButton = document.querySelector('.button-next')
function nextSlide(slide) {
for (slide = 0; slide < slidesCount; slide++) {
slidesContainer.style.transform = 'translateX(-' + (slide * slideWidth) + 'px)'
}
}
nextButton.addEventListener('click', function() {
nextSlide()
})
The issue I have is that when I click on the next button, the slider goes all the way at the end of my array, thus skipping all the images in between.
What would be the best way to have my for loop stop at each image and go again when the button is clicked?

The reason it is skipping to the end with each click is: the for() loop. You are cycling through all of the slides — generating a new translateX coordinate with each pass – on every click. Leaving you with the last value every time.
The answer CheapGamer gave defines a pattern to avoid the for() loop trap by keeping track of the current “slide” index outside of the nextSlide() handler.
let current = 0; // <- independent index reference
function nextSlide(slide) {
if (current < slidesCount) {
slidesContainer.style.transform = 'translateX(-' + (current * slideWidth) + 'px)';
current++; // <- increment the index
}
}
// I changed the `slide` reference in `(slide * slideWidth)` to `current` to reflect the intent of the code
This takes care of incrementing you through the carousel until current equals 3. (The slide argument in nextSlide(slide) isn’t necessary.)

let current = 0;
function nextSlide(slide) {
if (current < slidesCount) {
slidesContainer.style.transform = 'translateX(-' + (slide * slideWidth) + 'px)';
current++;
}
}

I might not exactly understand what you try to do or why you intend to use a for loop but if it's just about selecting the next slide you may go with this:
var currentSlide = 0;
function nextSlide() {
//make sure currentSlide is in range
currentSlide = (currentSlide >= slidesCount) ? 0 : ++currentSlide;
slidesContainer.style.transform = 'translateX(-' + (currentSlide * slideWidth) + 'px)';
}
nextButton.addEventListener('click', nextSlide);
or a little bit more flexible:
var currentSlide = 0;
function nextSlide(direction /* Number */) {
if(!direction) direction = 1; //default
setSlide(currentSlide + direction % slidesCount);
}
function setSlide(index) {
if(index === currentSlide) return;
//make sure index is in range
while(index >= slidesCount) index -= slidesCount;
while(index < 0) index += slidesCount;
slidesContainer.style.transform = 'translateX(-' + (index * slideWidth) + 'px)';
currentSlide = index;
}
nextButton.addEventListener('click', function() {
nextSlide(this.dataset["direction"]); //by using data you don't need two different button classes
});
But if you insist on using a loop I'm afraid to tell that it's inappropriate in this case since the calculation of translateX is based on a given value.

Related

Javascript: slideshow not slide when click

I have simple code where is slideshow which automatic slides every 5000ms.
Now I tried to make button which when I click on this button next image will not slide every 5000ms but when I click.
When I make code like this browser giving me errors.
Is there any solutions or I need make ned slideshow?
This is original code:
function cycleBackgrounds() {
var index = 0;
$imageEls = $('.container .slide');
setInterval(function () {
index = index + 1 < $imageEls.length ? index + 1 : 0;
$imageEls.eq(index).addClass('show');
$imageEls.eq(index - 1).removeClass('show');
}, 5000);
};
$(function () {
cycleBackgrounds();
});
This is added code:
function rightSlide() {
index = index + 1 < $imageEls.length ? index + 1 : 0;
$imageEls.eq(index).addClass('show');
$imageEls.eq(index - 1).removeClass('show');
}
EDIT added HTML
<section class="slide show" style="background-image: url('https://s7img.ftdi.com/is/image/ProvideCommerce/FTD_19_EDAY_19M3_HP_HEROBANNER?$ftd-product-banner-lv$');">
<div class="slide-content-wrapper">
<div class="slide-content">
<h2>02</h2>
</div>
</div>
</section>
<section class="slide" style="background-image: url('https://s7img.ftdi.com/is/image/ProvideCommerce/FTD_19_EDAY_19M3_HP_HEROBANNER?$ftd-product-banner-lv$');">
<div class="slide-content-wrapper right">
<div class="slide-content">
<h2>01</h2>
</div>
</div>
</section>
The problem is that you are creating an interval and then never clearing it. This means that once the interval is created it will keep going on forever (currently). You can read more about intervals here.
To briefly explain how to solve it:
You need to assign the interval to a variable
When you want to manually change images then clear the interval
Code snippet from the site:
var myVar = setInterval(myTimer, 1000);
function myTimer() {
var d = new Date();
var t = d.toLocaleTimeString();
document.getElementById("demo").innerHTML = t;
}
function myStopFunction() {
clearInterval(myVar);
}
Inside of your code, when creating the interval you need to assign it into a variable and inside of the function rightSlide() you would need to clear it clearInterval(<yourIntervalHere>);
var intervalVariable = setInterval(function () {
index = index + 1 < $imageEls.length ? index + 1 : 0;
$imageEls.eq(index).addClass('show');
$imageEls.eq(index - 1).removeClass('show');
}, 5000);
function rightSlide() {
clearInterval(intervalVariable);
index = index + 1 < $imageEls.length ? index + 1 : 0;
$imageEls.eq(index).addClass('show');
$imageEls.eq(index - 1).removeClass('show');
}
You need to clear the interval but that's not the only problem:
Probably, the $imageEls and index variables are not in the scope of your custom click handler. It is definitely not the cleanest solution, but for now we will add them to the global window object
This is how I would write it (untested):
function cycleBackgrounds() {
window.index = (window.index + 1 < window.$imageEls.length) ? window.index + 1 : 0;
window.$imageEls.eq(index).addClass('show');
window.$imageEls.eq(index - 1).removeClass('show');
}
$(function () {
// add the new variables to window so they are globally accessible
window.index = 0;
window.$imageEls = $('.container .slide');
// start sliding images
window.slideshow_interval = setInterval(cycleBackgrounds, 5000);
// register onClick handler for the button with id "myButton"
$('#myButton').on('click', function(){
if (window.slideshow_interval != -1){
clearInterval(window.slideshow_interval);
window.slideshow_interval = -1;
}
cycleBackgrounds();
});
});

addEventListener only works once

I have an event listener. Inside it I'm looping through 3 images and applying style translateX(350px) to them. It works perfectly fine but it only works once.
I click right once and the images move to the right but if I click right again the images do not move. How do I make the Event Listener fire multiple times so images move multiple times? There is a similar question on Stack Overflow but I could not understand.
HTML:
<div id='container'>
<div class='image-container'>
<img class='move' src='images/news1.jpg'>
<img class='move' src='images/news2.jpg'>
<img class='move' src='images/news3.jpg'>
</div>
</div>
<a href="#" id='arrow-left'>left</a>
<a href="#" id='arrow-right'>right</a>
JavaScript:
let imageContainer = document.querySelector('.image-container');
let arrowLeft = document.getElementById('arrow-left');
let arrowRight = document.getElementById('arrow-right');
let images = document.getElementsByClassName('move');
arrowRight.addEventListener('click', function() {
for (i = 0; i < images.length; i++) {
images[i].style.transition = "0.5s";
images[i].style.transform = 'translateX(350px)';
}
});
You may need to use an accumulator for your transformations so that they remember their previous translation state, e.g, 350 the first time, 700 the 2nd, ... etc.:
try this:
var accum = 350;
let imageContainer = document.querySelector('.image-container');
let arrowLeft = document.getElementById('arrow-left');
let arrowRight = document.getElementById('arrow-right');
let images = document.getElementsByClassName('move');
arrowRight.addEventListener('click' , function() {
for (let i = 0 ; i < images.length; i++) {
images[i].style.transition = "0.5s";
images[i].style.transform = 'translateX(' + accum + 'px)';
}
accum+= 350;
});
<div id='container'>
<div class='image-container'>
<img class='move' src='images/news1.jpg'>
<img class='move' src='images/news2.jpg'>
<img class='move' src='images/news3.jpg'>
</div>
</div>
<a href="#" id='arrow-left'>left</a>
<a href="#" id='arrow-right'>right</a>
DEMO: http://jsfiddle.net/crmqj91t/15/
TranslateX takes the reference of the initial render position. So everytime you set translatex by 350px it remains at the same point with respect to its origin.
I've added a step counter, which sets the correct distance from the origin on each step.
let imageContainer = document.querySelector('.image-container');
let arrowLeft = document.getElementById('arrow-left');
let arrowRight = document.getElementById('arrow-right');
let images = document.getElementsByClassName('move');
let step = 1;
arrowRight.addEventListener('click', function() {
for (i = 0; i < images.length; i++) {
images[i].style.transition = "0.5s";
images[i].style.transform = 'translateX(' + step * 50 + 'px)';
}
step++;
});

Slider Images working correctly for right cursor but not left

I have created a website for a friend which includes a slideshow with his most recent Instagram posts. The slideshow has a right and left arrow cursor.
The right cursor is working how I want it to; it shows each image from the array upon each click, and keeps going regardless of how many times the user clicks the right cursor. When it reaches the last image in the array, it starts at the first image again due to an if statement put in place.
However, I am having trouble with the left cursor and I suspect it is the counter variable? With the current code, what happens is when I click the left cursor (with the page refreshed and without even clicking on the right cursor), it goes to the second image in the array index1, rather than the last. Then I click the left cursor again without any change happening, then when I click it the third time it goes to the last image in the array and works as it should until it reaches the second image in the array again - because after that it does not go to the first image, it skips the first image after another click of nothing happening and then goes to the last image in the array. Repeats itself in that manner (sorry for going so in-detail, but I want people to get an idea of whats happening here if the code doesn't help).
var sliderImages = [];
var counter = 1;
sliderImages[0] = "images/i1.png";
sliderImages[1] = "images/i2.png";
sliderImages[2] = "images/i3.png";
sliderImages[3] = "images/i4.png";
sliderImages[4] = "images/i5.png";
$("#right-arrow").click(function() {
$(".active").attr("src", sliderImages[counter]);
counter++;
$('#count').text(counter);
if (counter >= sliderImages.length) {
counter = 0;
}
});
$("#left-arrow").click(function() {
$(".active").attr("src", sliderImages[counter]);
counter--;
if (counter <= 0) {
counter = sliderImages.length
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section id="instagram-feed">
<div class="container">
<h2>INSTAGRAM GALLERY</h2>
<div class="insta-gallery">
<img src="images/left-arrow.png" class="arrow" id="left-arrow">
<img src="images/i1.png" class="active">
<img src="images/right-arrow.png" class="arrow" id="right-arrow">
</div>
</div>
<div class="clear"></div>
</section>
When your page loads, you set counter to 1. When you click the left-arrow button, the first thing you do is set the image to the counter value, and so you set the image to 1. (Remember, arrays are 0-indexed, meaning 1 refers to the second item).
You'd be better off if counter was referring to the current image, not trying to assume the upcoming one. See my comments in the modified code below for more information.
var sliderImages = [];
var counter = 0; //Start with first image instead of second
sliderImages[0] = "images/i1.png";
sliderImages[1] = "images/i2.png";
sliderImages[2] = "images/i3.png";
sliderImages[3] = "images/i4.png";
sliderImages[4] = "images/i5.png";
$("#right-arrow").click(function() {
counter++; //Moving forward by one
if (counter > sliderImages.length-1) counter = 0; //Wrap-around if we exceed length-1
$(".active").attr("src", sliderImages[counter]); //Update img src
});
$("#left-arrow").click(function() {
counter--; //Moving backward by one
if (counter < 0) counter = sliderImages.length-1; //Wrap-around if negative
$(".active").attr("src", sliderImages[counter]); //Update img src
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section id="instagram-feed">
<div class="container">
<h2>INSTAGRAM GALLERY</h2>
<div class="insta-gallery">
<img src="images/left-arrow.png" class="arrow" id="left-arrow">
<img src="http://via.placeholder.com/350x150" class="active">
<img src="images/right-arrow.png" class="arrow" id="right-arrow">
</div>
</div>
<div class="clear"></div>
</section>
Use a counter as if you're handling indexes, so set it initially at 0.
Here's the basic logic:
var sliderImages = [
"//placehold.it/100x100/0bf?text=O",
"//placehold.it/100x100/f0b?text=1",
"//placehold.it/100x100/0fb?text=2",
"//placehold.it/100x100/fb0?text=3",
"//placehold.it/100x100/b0f?text=4"
];
var n = sliderImages.length; // Total slides
var c = 0; // Counter
function anim () {
$("#mainImage").attr("src", sliderImages[c]);
}
$("#prev").on("click", function() {
--c; // Pre-decrement
if ( c < 0 ) { c = n-1; } // If lower than 0 - go to last slide
anim(); // animate
});
$("#next").on("click", function() {
++c; // Pre-increment
if ( c > n-1 ) { c = 0; } // If greater than num of slides - go to first slide
anim(); // animate
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img id="mainImage" src="//placehold.it/100x100/0bf?text=O">
<br>
<button id="prev">←</button>
<button id="next">→</button>
<span id="count"></span>
Or here's a neater extracted formula of the above:
var sliderImages = [
"//placehold.it/100x100/0bf?text=O",
"//placehold.it/100x100/f0b?text=1",
"//placehold.it/100x100/0fb?text=2",
"//placehold.it/100x100/fb0?text=3",
"//placehold.it/100x100/b0f?text=4"
];
var n = sliderImages.length; // Total slides
var c = 0; // Counter
function anim () {
c = c<0 ? n-1 : c%n; // Fix counter
$("#mainImage").attr("src", sliderImages[c]); // Animate (or whatever)
}
$("#prev, #next").on("click", function() {
c = this.id==="next" ? ++c : --c; // Increement or decrement
anim(); // Animate
});
// If you have bullets than you can simply do like:
$(".bullet").on("click", function() {
c = $(this).index();
anim();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img id="mainImage" src="//placehold.it/100x100/0bf?text=O">
<br>
<button id="prev">←</button>
<button id="next">→</button>
<span id="count"></span>
Updated your code a bit :
var sliderImages = [];
var counter = 0;
sliderImages[0] = "images/i1.png";
sliderImages[1] = "images/i2.png";
sliderImages[2] = "images/i3.png";
sliderImages[3] = "images/i4.png";
sliderImages[4] = "images/i5.png";
$("#right-arrow").click(function() {
counter++;
$(".active").attr("src", sliderImages[counter]);
$('#count').text(counter);
if (counter >= sliderImages.length) {
counter = 0;
}
});
$("#left-arrow").click(function() {
counter--;
$(".active").attr("src", sliderImages[counter]);
if (counter <= 0) {
counter = sliderImages.length - 1;
}
});

setInterval increment index mystery

I am bangging my head against a wall, I cant figure out what is happening when I try increment my index value from outside my function.
So I starts off as 0, great! Each loop through i gets i +1 (this all seems great) ... but when I click #sliderNext you will see I dont add to the i value, yet it still increments the i value (why???) That means when I click prev I have to decrease the value by 2 instead of i-- (again, why?) ... am I being thick and not seeing something obvious?
Perhaps a better way to add prev + next (one that does not stop the setinterval completely)
$.when( loadImages() ).done(function(a1){
var i = 0;
var numberOfImgs = imgArr.length;
function sliderRotate(passi){
$('#autoSlider').html(imgArr[i]); //show with current i index
i++; //it should increment AFTER image has shown
if (i >= numberOfImgs || i < 0){ i = 0; }
}
sliderRotate();
intervalID = setInterval(sliderRotate, 3000);
//prev + next clicks
$('#sliderNext').on( 'click' , function(){
clearTimeout(intervalID);
//x = i + 1;
sliderRotate();
});
$('#sliderPrev').on( 'click' , function(){
clearTimeout(intervalID);
if ( i === 0 ){ i = imgArr.length -2; } //this only kind of works if I click twice on the first image
else{i = i - 2; }
sliderRotate();
});
});// end of when
Here is a snippet example:
$(document).ready(function(){
var imgArr = [
'<img src="http://www.freedigitalphotos.net/images/img/homepage/87357.jpg">',
'<img src="http://assets.barcroftmedia.com.s3-website-eu-west-1.amazonaws.com/assets/images/recent-images-11.jpg">',
'<img src="https://www.nasa.gov/sites/default/files/styles/image_card_4x3_ratio/public/thumbnails/image/pia20645_main.jpg?itok=dLn7SngD">',
'<img src="https://www.nasa.gov/sites/default/files/styles/image_card_4x3_ratio/public/thumbnails/image/pia18368-1041.jpg?itok=Fkc2j_kw">',
'<img src="http://www.irishtimes.com/polopoly_fs/1.2527148.1454955520!/image/image.jpg_gen/derivatives/landscape_685/image.jpg">',
'<img src="http://www.gettyimages.in/gi-resources/images/Homepage/Hero/US/Feb2016/video-481880130.jpg">'
];
var i = 0;
var numberOfImgs = imgArr.length;
function sliderRotate(passi){
$('#autoSlider').html(imgArr[i]);
i++; //should increment here, not before???
if (i >= numberOfImgs || i < 0){ i = 0; }
}
sliderRotate();
intervalID = setInterval(sliderRotate, 3000);
//prev + next clicks
$('#sliderNext').on( 'click' , function(){
clearTimeout(intervalID);
//x = i + 1;
sliderRotate();
});
$('#sliderPrev').on( 'click' , function(){
clearTimeout(intervalID);
if ( i === 0 ){ i = imgArr.length -2; } //kindah works, but still buggy
else{i = i - 2; }
sliderRotate();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="sliderContainer">
<div id="sliderNext">Next</div><br><br><br>
<div id="sliderPrev">Prev</div>
<div id="autoSlider"></div>
</div>
Initial value of i is 0. sliderRotate function renders the first image (at index 0) and increments i by 1. In the next execution of this function the second image (at index 1) will be shown and i will have a value 2.
Now, you want to get back to the previous image (at index 0). But value of i is 2. You have to show image at index i - 2.
You are calling sliderRotate():
$('#sliderNext').on( 'click' , function(){
clearTimeout(intervalID);
//x = i + 1;
**sliderRotate();**
});
And that will increment it by 1:
function sliderRotate(passi){
$('#autoSlider').html(imgArr[i]);
i++; //should increment here, not before???
if (i >= numberOfImgs || i < 0){ i = 0; }
}
Same for "prev", you are adding 1 when you call sliderRotate(), that is why you need to subtract 2.
Here is a working example with your code: https://jsfiddle.net/owbL084z/2/

JavaScript Slider Effect Not Consistant

I have created a slider so that when you click a button a section of content will appear from the side, the next click the section will come from the top and so on so on, however the first few slides are not consistant and all slide the same way (The side).
If someone could have a look and find out why this is happening it would be great:
<div id="slider">
<section class="horizontal-gallery">
<img src="images/pekapeka/peka1.jpg" class="init-hidden" id="1-slide" rel="right"/>
<p id="1-text" class="horizontal-gallery-text">This is the first image in the gallery </p>
</section>
<section class="vertical-gallery">
<img src="images/pekapeka/peka2.jpg" class="picture2 init-hidden" id="2-slide" rel="right" />
<p id="2-text" class="vertical-gallery-text init-hidden">This is the second image in the gallery, it should be sliding down</p>
</section>
<section class="horizontal-gallery">
<img src="images/pekapeka/peka3.jpg" class="picture3 init-hidden" id="3-slide" rel="up" />
<p id="3-text" class="horizontal-gallery-text text-3 init-hidden">This is the third image in the gallery it should be sliding in from the side </p>
</section>
JS:
var totalslides = '5';
var slidenum = 0;
var slidenext = 0;
var slideType = '';
$(function(){
$('#gallery-next').data('counter', 0);
$('#gallery-next').click(function() {
slidenum = parseInt($('#gallery-next').data('counter'));
slidenext = slidenum+1
slideType = $('#'+slidenum+'-slide').attr('rel')
//alert('Next slideType is: ' + slideType)
//hide(slide) is a jQueryUI function, so ensure you include that lib
$('#'+slidenext+'-slide').show('slide',{direction:slideType}, 1000);
$('#'+slidenum+'-slide').delay(600).fadeOut(600);
$('#'+slidenext+'-text').delay(1200).fadeIn();
$('#'+slidenum+'-text').fadeOut(400);
slidenum = slidenum % totalslides + 1;
$('#gallery-next').data('counter',slidenum);
console.log(slideType);
});
});
And a link: http://luvly.co.nz/space/te-horo-beach-house.html
I took the liberty of fixing the entire script, reproduced here: http://jsfiddle.net/samliew/waTDr/31/
var totalslides = 6;
var slidenum = 0;
var slidenext = 0;
$(function () {
var $slider = $('#slider');
var $slides = $slider.find('img');
var $slideTexts = $slider.find('p');
// hide all except first slide
$slides.hide().eq(0).show();
$slideTexts.hide().eq(0).show();
$('#gallery-next').data('counter', 0);
$('#gallery-next').click(function () {
slidenext = slidenum + 1;
if(slidenext >= totalslides) slidenext = 0;
var slideType = $slides.eq(slidenext).attr('rel');
console.log(slidenum + ', ' + slidenext + ': ' + slideType);
// hide(slide) is a jQueryUI function, so ensure you include that lib
$slides.eq(slidenext).show('slide', {
direction: slideType
}, 1000);
$slides.eq(slidenum).delay(600).fadeOut(600);
$slideTexts.eq(slidenext).delay(1200).fadeIn();
$slideTexts.eq(slidenum).fadeOut(400);
slidenum++;
if(slidenum >= totalslides) slidenum = 0;
console.log(slidenum + ', ' + slidenext);
});
});
Also, there is something wrong with the CSS positioning of text-6, you might want to look into that.
its broken because the first time the thing executes, slidenum is 0. so when it trys to find
slideType = $('#'+slidenum+'-slide').attr('rel')
slideType is undefined because $('#0-slide') doesn't exist. so when you try to pass {direction:undefined} to your show() function, i'm assuming its defaulting to some direction you don't expect.
try initializing your slideNum variable to 1.

Categories