jQuery: animated slider pager - javascript

I've set up an animated slider using jQuery:
jsFiddle demo: http://jsfiddle.net/neal_fletcher/9zRDV/
The reason being I wanted to achieve a slight overhang on the slides, i.e. while viewing slide 1 you can see some of slide 2 etc. The slider works great, perfect in fact for what I'm after, now though I'm trying to figure out if it's possible to set up a pager for this slider, the aim of which being to click on a .slide-menu-item and the slider will slide to the relevant slide, if at all possible?
One other slight problem too, is it possible to animate the slider on load? Thus, the pager will slide every 5 seconds, but you can still navigate the slider using the pager / next and previous buttons?
Any suggestions would be greatly appreciated!
HTML:
<div class="outerwrapper">
<div class="innerwrapper">
<div class="inner-slide">SLIDE 01</div>
<div class="inner-slide">SLIDE 02</div>
<div class="inner-slide">SLIDE 03</div>
<div class="inner-slide">SLIDE 04</div>
<div class="inner-slide">SLIDE 05</div>
<div class="inner-slide">SLIDE 06</div>
<div class="inner-slide">SLIDE 07</div>
</div>
</div>
<ul id="slide-menu">
<li id="one" class="slide-menu-item">01</li>
<li id="two" class="slide-menu-item">02</li>
<li id="three" class="slide-menu-item">03</li>
<li id="four" class="slide-menu-item">04</li>
<li id="five" class="slide-menu-item">05</li>
<li id="six" class="slide-menu-item">06</li>
<li id="seven" class="slide-menu-item">07</li>
</ul>
<div id="left">LEFT</div>
<div id="right">RIGHT</div>
CSS:
.outerwrapper {
position: absolute;
left: 50%;
height: 250px;
width: 400px; margin-left: -225px;
border: 1px solid black;
overflow: hidden;
padding-left: 50px;
}
.innerwrapper {
height: 250px;
width: 4000px;
}
.inner-slide {
height: 250px;
width: 350px;
float: left;
background: silver;
}
.innerwrapper div:nth-child(odd) {
background: silver;
}
.innerwrapper div:nth-child(even) {
background: red;
}
#left, #right {
position: absolute;
cursor: pointer;
}
#left {
left: 10px; bottom: 10px;
}
#right {
right: 10px; bottom: 10px;
}
#slide-menu {
position: absolute;
top: 250px;
list-style: none;
}
.slide-menu-item {
display: inline-block;
width: 50px;
cursor: pointer;
}
jQuery:
var animating = false,
slideWidth = $('.inner-slide').width(),
$wrapper = $('.outerwrapper'),
slideIndex = 2,
slideLen = $('.inner-slide').length,
build = function() {
$firstClone = $('.inner-slide').eq(0).clone();
$secondClone = $('.inner-slide').eq(1).clone();
$preLastClone = $('.inner-slide').eq(slideLen - 2).clone();
$lastClone = $('.inner-slide').eq(slideLen - 1).clone();
$wrapper.find('.innerwrapper').append($firstClone, $secondClone).prepend($preLastClone, $lastClone);
$wrapper.animate({
scrollLeft: '+=' + slideWidth * slideIndex + 'px'
}, 0);
},
slide = function(dir, speed) {
if(!animating) {
animating = true;
dir == 'right' ? slideIndex++ : slideIndex--;
slideIndex == slideLen - 1 ? slideIndex == 0 : '';
if(slideIndex == 0 && dir == 'left') {
//if the slide is at the beginning and going left
slideIndex = slideLen + 1;
$wrapper.animate({
scrollLeft: slideIndex * slideWidth + 'px'
}, 0, function() {
animating = false;
});
slideIndex--;
} else if(slideIndex == slideLen + 2 && dir == 'right') {
//if the slide is at the end and going right
slideIndex = 1;
$wrapper.animate({
scrollLeft: slideIndex * slideWidth + 'px'
}, 0, function() {
animating = false;
});
slideIndex++;
}
$wrapper.animate({
scrollLeft: slideIndex * slideWidth + 'px'
}, speed, function() {
animating = false;
});
}
};
$(function() {
build();
$('#right, #left').on('click', function() {
slide($(this).attr('id'), 600)
});
});

Add the slideTo function:
slideTo = function (index, speed) {
slideIndex = index+1;
$wrapper.animate(
{scrollLeft: slideIndex * slideWidth + 'px'},
speed, function () {animating = false;}
);
}
Then call it when you click one of the page buttons:
$('.slide-menu-item').click(function() {
var toSlideIndex = Math.round($(this).text());
slideTo(toSlideIndex, 600);
});
And then, to make it slide automatically every 5 seconds, add this:
setInterval(function() {slide("right", 600);}, 5000);
JSFiddle demo: http://jsfiddle.net/9zRDV/3/

for example ?
$('#yourFavouriteIdForButtonThree').click(function(){
slide('three', 600)
});

Related

Center horizontally child elements if their parent's width is 300% but each child's width 100%

I have a dynamic slider with two buttons left and right.
that means for each slide, the slide parent width increases by 100%. 2 slides * 100% = 200%. In example class="slider"; width:'200%'
I want to center each slide's text in the middle of the page. But i want the text to slide not in just slides container, but in its parent-parent width (class='carousel' in example).
Code below, is example how the slider is looking right now.
JavaScript, you should ignore this. Implemented it, for the code to work.
document.addEventListener('DOMContentLoaded', function() { //Display function after HTML is loaded
const left = document.querySelector('.left');
const right = document.querySelector('.right');
var slider = document.getElementById('slider');
var leftImg = document.getElementById('left');
var rightImg = document.getElementById('right');
var sections = document.querySelectorAll('.slide').length; // get number of slides
var sectionIndex = 1;
slider.style.width = ' ' + 100 * sections + '%';
function changeOpacity() {
if (sectionIndex == 1) {
leftImg.style.opacity = '0.4';
} else {
leftImg.style.opacity = '1';
}
if (sectionIndex == sections) {
rightImg.style.opacity = '0.4';
} else {
rightImg.style.opacity = '1';
}
}
left.addEventListener('click', function() {
var leftImg = document.getElementById('left');
sectionIndex = (sectionIndex > 1) ? sectionIndex - 1 : 1;
slider.style.transform = 'translate(' + (sectionIndex - 1) * (-100 / sections) + '%)';
changeOpacity();
});
right.addEventListener('click', function() {
sectionIndex = (sectionIndex < sections) ? sectionIndex + 1 : sections;
slider.style.transform = 'translate(' + (sectionIndex - 1) * (-100 / sections) + '%)';
changeOpacity();
});
})
.slider-container {
padding: 25px 0px;
width: 40%;
margin: auto;
}
.slider-container .carousel {
overflow: hidden;
height: 260px;
width: 100%;
border:solid 2px black;
position:relative;
}
.slider-container .slider {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
height: 100%;
-webkit-transition: .5s;
transition: .5s;
}
.slider-container .slider .slide {
width: 100%;
}
.slider-container .arrow-container {
width: 70px;
position: absolute;
bottom: 0;
}
<div class="slider-container mobile-container text-left">
<div class="carousel relative">
<div id="slider" class="slider">
<div class="slide">
<div class="author d-flex flex-column">
<h3>Ken Ludden</h3>
<span class="regularText">Director, Margot Fonteyn Academy of Ballet</span>
</div>
</div>
<div class="slide">
<div class="author d-flex flex-column">
<h3>Ken Ludden</h3>
<span class="regularText">Director, Margot Fonteyn Academy of Ballet</span>
</div>
</div>
</div>
</div>
<div class="controls">
<div class="arrow-container d-flex justify-content-between ">
<div>
<button class="left" id="left" style="opacity: 0.4;">Left </button>
</div>
<div>
<button class="right" id="right">Right</button>
</div>
</div>
</div>
</div>
</div>
The Snippet below is what i want. But i should be centered, and i don't know how.
I have tried using fl
document.addEventListener('DOMContentLoaded', function() { //Display function after HTML is loaded
const left = document.querySelector('.left');
const right = document.querySelector('.right');
var slider = document.getElementById('slider');
var leftImg = document.getElementById('left');
var rightImg = document.getElementById('right');
var sections = document.querySelectorAll('.slide').length; // get number of slides
var sectionIndex = 1;
slider.style.width = ' ' + 100 * sections + '%';
function changeOpacity() {
if (sectionIndex == 1) {
leftImg.style.opacity = '0.4';
} else {
leftImg.style.opacity = '1';
}
if (sectionIndex == sections) {
rightImg.style.opacity = '0.4';
} else {
rightImg.style.opacity = '1';
}
}
left.addEventListener('click', function() {
var leftImg = document.getElementById('left');
sectionIndex = (sectionIndex > 1) ? sectionIndex - 1 : 1;
slider.style.transform = 'translate(' + (sectionIndex - 1) * (-100 / sections) + '%)';
changeOpacity();
});
right.addEventListener('click', function() {
sectionIndex = (sectionIndex < sections) ? sectionIndex + 1 : sections;
slider.style.transform = 'translate(' + (sectionIndex - 1) * (-100 / sections) + '%)';
changeOpacity();
});
})
.slider-container {
margin: auto;
padding: 25px 0px;
}
.slider-container .carousel {
overflow: hidden;
height: 260px;
width: 80%; /* the width i want */
border: solid 2px black; /* the border for your understading */
position: relative;
}
.slider-container .slider {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
height: 100%;
-webkit-transition: .5s;
transition: .5s;
}
.slider-container .slider .slide {
width: 100%;
}
.slider-container .comment {
max-width: 352px;
padding: 30px 0px;
}
.slider-container .arrow-container {
width: 70px;
position: absolute;
bottom: 0;
}
<div class="slider-container mobile-container text-left">
<div class="carousel relative">
<div id="slider" class="slider">
<div class="slide">
<div class="author d-flex flex-column">
<h3>Ken Ludden</h3>
<span class="regularText">Director, Margot Fonteyn Academy of Ballet</span>
</div>
</div>
<div class="slide">
<div class="author d-flex flex-column">
<h3>Ken Ludden</h3>
<span class="regularText">Director, Margot Fonteyn Academy of Ballet</span>
</div>
</div>
</div>
<div class="controls">
<div class="arrow-container d-flex justify-content-between ">
<div>
<button class="left" id="left" style="opacity: 0.4;">Left </button>
</div>
<div>
<button class="right" id="right">Right</button>
</div>
</div>
</div>
</div>
</div>
</div>
You can see in this snippet that text is sliding from a lot further right than the previous example.
I need to center the slide, because i want the same for left side.
I have tried using flex-column, align-items:center on class="slide". And it works fine, but the class="controls" aren't centering because they are position:absolute and i tried to putting them elsewhere, but it didnt work..
I really hope you guys did understand what i want and really hope that i recieve atleast some suggestions. This is my 1st question, sorry for long code.
Thank you anyway :)
Your carousel is 80% of the width, so if you want that to be centered, you can do: margin: 0 auto on the carousel class.

Display progress bar as scroll in multiple elements

I am trying to create a post page where user scroll to view the posts. There are multiple posts with a sidebar so I want to display a progress bar to indicate the article position.
The code I wrote for this is working good when I navigate to the first element but not for the elements after this.
Here is the code. I tried to set up a fiddle here I want to achieve something like this in the sidebar Reference link
var contentSections = $('.single_page_post');
jQuery(window).on('scroll', function () {
updateNavigation();
});
function updateNavigation() {
contentSections.each(function () {
$this = $(this);
var theID = $this.attr("id");
if (($this.offset().top - $(window).height() / 2 < $(window).scrollTop()) && ($this.offset().top + $this.height() - $(window).height() / 2 > $(window).scrollTop())) {
var s = $(window).scrollTop(),
d = $this.height(),
c = $this.offset().top;
var scrollPercent = (s / (d - c)) * 100;
var progressheight = 100-scrollPercent;
$("a[href='#" + theID + "']").prev().css({'height' : progressheight+"%", 'display' : 'block'});
$("a[href='#" + theID + "']").parents('.post_page_sidebar').addClass("current");
} else {
$("a[href='#" + theID + "']").prev().css({'display' : 'none'});
$("a[href='#" + theID + "']").parents('.post_page_sidebar').removeClass("current");
}
});
}
.content_area {
width: 60%;
float:left;
}
.post_page_sidebar {
position: relative;
}
.post_progress {
position: absolute;
width: 5px;
background: red;
bottom:0px;
}
a {
padding: 10px 10px 10px 7px;
display: inline-block;
}
li {
list-style: none;
}
.sidebar {
width: 30%;
position: fixed;
top: 0px;
}
.single_page_post {
height: 500px;
border: 2px solid #e2e2e2;
margin-top: 5px;
margin-left:200px;
width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="sidebar">
<ul>
<li id="sidebar_post_267" class="post_page_sidebar">
<div class="post_progress"></div>
Dummy Post 4
</li>
<li id="sidebar_post_263" class="post_page_sidebar">
<div class="post_progress"></div>
Dummy Post 3
</li>
<li id="sidebar_post_261" class="post_page_sidebar">
<div class="post_progress"></div>
Dummy Post 2
</li>
<li id="sidebar_post_131" class="post_page_sidebar">
<div class="post_progress"></div>
Test Post
</li>
</ul>
</div>
<div class="content_area">
<div class="single_page_post" id="post_section_267">
</div>
<div class="single_page_post" id="post_section_263">
</div>
<div class="single_page_post" id="post_section_261">
</div>
<div class="single_page_post" id="post_section_131">
</div>
</div>
There's two issues with your code. The first one is that, logically, you would not be wanting to subtract $this.offset().top from $this.height() but rather from $(window).scrollTop() giving you:
var scrollPercent = ((s-c) / (d)) * 100;
The second one is that your logic to switch which article is the currently visible one is convoluted and wrong. The statement you posted switches active article "too early" and therefore returns something a long the lines of "the user read -30% of this article". It is a lot easier to just check for each item whether:
$this.offset().top - $(window).scrollTop() < 0
to determine if it is completely in the viewport.
These two changes give you the following snippet:
var contentSections = $('.single_page_post');
jQuery(window).on('scroll', function () {
updateNavigation();
});
function updateNavigation() {
contentSections.each(function () {
$this = $(this);
var theID = $this.attr("id");
if ($this.offset().top - $(window).scrollTop() < 0) {
var s = $(window).scrollTop()-13,
d = $this.outerHeight(),
c = $this.offset().top;
var scrollPercent = ((s-c) / (d)) * 100;
var progressheight = 100-scrollPercent;
$("a[href='#" + theID + "']").prev().css({'height' : progressheight+"%", 'display' : 'block'});
$("a[href='#" + theID + "']").parents('.post_page_sidebar').addClass("current");
} else {
$("a[href='#" + theID + "']").prev().css({'display' : 'none'});
$("a[href='#" + theID + "']").parents('.post_page_sidebar').removeClass("current");
}
});
}
.content_area {
width: 60%;
float:left;
}
.post_page_sidebar {
position: relative;
}
.post_progress {
position: absolute;
width: 5px;
background: red;
bottom:0px;
}
a {
padding: 10px 10px 10px 7px;
display: inline-block;
}
li {
list-style: none;
}
.sidebar {
width: 30%;
position: fixed;
top: 0px;
}
.single_page_post {
height: 500px;
border: 2px solid #e2e2e2;
margin-top: 5px;
margin-left:200px;
width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="sidebar">
<ul>
<li id="sidebar_post_267" class="post_page_sidebar">
<div class="post_progress"></div>
Dummy Post 4
</li>
<li id="sidebar_post_263" class="post_page_sidebar">
<div class="post_progress"></div>
Dummy Post 3
</li>
<li id="sidebar_post_261" class="post_page_sidebar">
<div class="post_progress"></div>
Dummy Post 2
</li>
<li id="sidebar_post_131" class="post_page_sidebar">
<div class="post_progress"></div>
Test Post
</li>
</ul>
</div>
<div class="content_area">
<div class="single_page_post" id="post_section_267">
</div>
<div class="single_page_post" id="post_section_263">
</div>
<div class="single_page_post" id="post_section_261">
</div>
<div class="single_page_post" id="post_section_131">
</div>
</div>

setInterval issue in custom jquery image slider with both auto slide and buttons

I am creating a custom image slider with custom slide effect in jQuery which has both next & previous buttons and also slides automatically with 5 seconds timeout. Although it works nicely in a quick look but sometimes( I dont know exactly when, maybe when I press the buttons or if I leave it open for some time and minimize the window) the iterval bugs and the slides change after 1 second or less. Also when i press the button i tell it to 1) clear iterval 2) change slide 3) set interval again which means that after i change a slide with the button the timer is set to 5 seconds from the start but this is not happening all the times.Here is the code.
$(document).ready(function() {
'use strict';
var $carousel = $('.carousel');
var $nextBtn = $('#next');
var $prevBtn = $('#prev');
var animationSpeed = 1000;
var pause = 5000;
var interval;
function nextSlide() {
$('.carousel__list').animate({
left: '-200%'
}, 500, function() {
$('.carousel__list').css('left', '-100%');
$('.carousel__item').last().after($('.carousel__item').first());
});
}
function prevSlide() {
$('.carousel__list').animate({
left: '0%'
}, 400, function() {
$('.carousel__list').css('left', '-100%');
$('.carousel__item').first().before($('.carousel__item').last());
});
}
function startSlider() {
interval = setInterval(function() {
nextSlide();
}, pause);
}
function stopSlider() {
clearInterval(interval);
}
$carousel.on('mouseenter', stopSlider).on('mouseleave', startSlider);
startSlider();
$nextBtn.on('click', function() {
stopSlider();
nextSlide();
startSlider();
});
$prevBtn.on('click', function() {
stopSlider();
prevSlide();
startSlider();
});
});
*,
*::after,
*::before {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.carousel {
width: 100%;
height: 65vh;
overflow: hidden;
position: relative;
}
.carousel__list {
width: 400%;
height: 100%;
left: -100%;
position: relative;
list-style: none;
}
.carousel__item {
width: calc(100% / 4);
height: 100%;
float: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="carousel">
<ul class="carousel__list">
<li class="carousel__item" style="background-color: red"></li>
<li class="carousel__item" style="background-color: green"></li>
<li class="carousel__item" style="background-color: blue"></li>
<li class="carousel__item" style="background-color: yellow"></li>
</ul>
</section>
<button id="prev">PREVIOUS</button>
<button id="next">NEXT</button>
And here is a codepen: https://codepen.io/anon/pen/erpyJj
You are creating more intervals than you think and you don't actually clear each one because you overwrite the interval variable and then you don't a have a reference to the previous intervals, which may still be active.
What you could do is put every interval you create in an array, then when you need to stop all intervals, iterate through that array, clear each interval and empty the array.
// ...
var intervals = [];
// ...
function stopSlider() {
console.log("stopSlider() intervals (Before clear): ", intervals);
intervals.forEach(function(interval) {
clearInterval(interval); // stop one interval
});
intervals = []; // clear the array
console.log("stopSlider() intervals (After clear): ", intervals);
}
Here is your demo with many console logs. You can see that it doesn't matter how much you click on any button, the slider only automatically slides every 5 s.
$(document).ready(function() {
"use strict";
//cache dom elements
var $carousel = $(".carousel");
var $nextBtn = $("#next");
var $prevBtn = $("#prev");
var animationSpeed = 1000;
var pause = 5000;
var intervals = [];
function nextSlide() {
console.log("nextSlide() intervals: ", intervals);
$(".carousel__list").animate({
left: "-200%"
}, 500, function() {
$(".carousel__list").css("left", "-100%");
$(".carousel__item")
.last()
.after($(".carousel__item").first());
});
}
function prevSlide() {
console.log("prevSlide() intervals: ", intervals);
$(".carousel__list").animate({
left: "0%"
}, 400, function() {
$(".carousel__list").css("left", "-100%");
$(".carousel__item")
.first()
.before($(".carousel__item").last());
});
}
function startSlider() {
console.log("startSlider() interval (BEFORE): ", intervals);
var interval = setInterval(function() {
nextSlide();
}, pause);
intervals.push(interval);
console.log("startSlider() interval (AFTER): ", intervals);
}
function stopSlider() {
console.log("stopSlider() intervals (Before clear): ", intervals);
intervals.forEach(function(interval) {
clearInterval(interval); // stop one interval
});
intervals = []; // clear the array
console.log("stopSlider() intervals (After clear): ", intervals);
}
$carousel.on("mouseenter", stopSlider).on("mouseleave", startSlider);
startSlider();
$nextBtn.on("click", function() {
stopSlider();
nextSlide();
startSlider();
});
$prevBtn.on("click", function() {
stopSlider();
prevSlide();
startSlider();
});
});
*,
*::after,
*::before {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.carousel {
width: 100%;
height: 20vh;
overflow: hidden;
position: relative;
}
.carousel__list {
width: 400%;
height: 100%;
left: -100%;
position: relative;
list-style: none;
}
.carousel__item {
width: calc(100% / 4);
height: 100%;
float: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="carousel">
<ul class="carousel__list">
<li class="carousel__item" style="background-color: red"></li>
<li class="carousel__item" style="background-color: green"></li>
<li class="carousel__item" style="background-color: blue"></li>
<li class="carousel__item" style="background-color: yellow"></li>
</ul>
</section>
<button id="prev">PREVIOUS</button>
<button id="next">NEXT</button>

Creating a dynamic width items for carousel slider

I'm currently in the middle making my carousel responsive. So far I've managed to make it responsive only if the user resizes and refreshes browser only then it will resize programmatically. How can I make it resize without having to refresh the browser.
Update:
I tried working with the answers below. Currently it stays on a fixed value even if I resize browser. Inside my css there is no fixed value placed
$(document).ready(function() {
var sliderWidth = 0;
var sliderContainer = $('.slider-container');
var slider = $('.slider-container .slider');
var sliderItems = $('.slider li');
var sliderContainerWidth = sliderContainer.width();
sliderItems.width(sliderContainerWidth / 2);
$('.slider-container ul.slider').children().each(function() {
sliderWidth += $(this).outerWidth();
slider.width(sliderWidth + 1000);
});
$('.btns .prev').on('click', function() {
prevSlide();
})
function prevSlide() {
var sliderItemsWidth = sliderItems.width();
var leftIndent = parseInt($(sliderItems).css('left')) - sliderItemsWidth;
function animate() {
$('.slider-container .slider:not(:animated)').animate({
'left': leftIndent
}, 100)
}
animate();
}
})
.wrapper {
max-width: 1280px;
margin: 0 auto;
background-color: #ccc;
}
.wrapper .slider-container {
float: left;
position: relative;
overflow: hidden;
width: 100%;
background-color: beige;
}
.wrapper .slider-container .slider {
display: flex;
flex-wrap: wrap;
position: relative;
}
.wrapper .slider-container .slider li {
height: 300px;
background-color: #ccc;
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="slider-container">
<ul class="slider">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<ul class="btns">
<li class="prev">prev</li>
<li class="next">next</li>
</ul>
</div>
</div>
As per my comments, you can put the resizing bits into a function and call that on window resize:
$(document).ready(function() {
var sliderContainer = $('.slider-container');
var slider = $('.slider-container .slider');
var sliderItems = $('.slider li');
function resize() {
var sliderWidth = 0;
var sliderContainerWidth = sliderContainer.width();
sliderItems.width(sliderContainerWidth / 2);
$('.slider-container ul.slider').children().each(function() {
sliderWidth += $(this).outerWidth();
slider.width(sliderWidth + 1000);
});
}
$('.btns .prev').on('click', function() {
prevSlide();
})
function prevSlide() {
var sliderItemsWidth = sliderItems.width();
var leftIndent = parseInt($(sliderItems).css('left')) - sliderItemsWidth;
function animate() {
$('.slider-container .slider:not(:animated)').animate({
'left': leftIndent
}, 100)
}
animate();
}
resize(); // call onload
$(window).on('resize', function () {
resize(); // call when browser is resized
});
})

Using a block variable to stop multiple events running

I have a jQuery slider that will cycle through images from to left to right.
There are also buttons on the left and right hand side of the slider that will allow the user to scroll through the images manually if they want to.
The problem I'm having is that if these buttons are clicked multiple times the images will slide off the page, this is because the events are fired before the left property of the list is beyond its boundary.
I am trying to use a variable to block the user being able to fire these events by checking if a current animation is already taking place, but the events still seem to fire. Here is a working jsFiddle that shows the problem. http://jsfiddle.net/25tt5vmp/10/
Here is the jQuery function:
$(document).ready(function () {
var myTimer = setInterval(slide, 2000);
var blockedSlider = false;
function slide() {
var left = $('#sliderList').css('left');
left = left.substring(0, left.length - 2);
if (left <= -800) {
$('#sliderList').css('left', '-400px');
var slide = $('#sliderList li:first');
$('#sliderList').children('li:first').remove();
$('#sliderList').append(slide);
$('#sliderList').animate({ left: "-=400px" }, "slow", "swing");
}
else {
$('#sliderList').animate({ left: "-=400" }, "slow", "swing");
}
}
$('#sliderLeft').click(function () {
if (blockedSlider == false) {
blockedSlider = true;
var left = $('#sliderList').css('left');
left = left.substring(0, left.length - 2);
if (left <= -800) {
$('#sliderList').css('left', '-400px');
var slide = $('#sliderList li:first');
$('#sliderList').children('li:first').remove();
$('#sliderList').append(slide);
$('#sliderList').animate({ left: "-=400px" }, "slow", "swing");
clearInterval(myTimer);
myTimer = setInterval(slide, 2000);
}
else {
$('#sliderList').animate({ left: "-=400" }, "slow", "swing");
clearInterval(myTimer);
myTimer = setInterval(slide, 2000);
}
blockedSlider = false;
}
});
$('#sliderRight').click(function () {
if (blockedSlider == false) {
blockedSlider = true;
var left = $('#sliderList').css('left');
left = left.substring(0, left.length - 2);
if (left >= 0) {
$('#sliderList').css('left', '-400px');
var slide = $('#sliderList li:last');
$('#sliderList').children('li:last').remove();
$('#sliderList').prepend(slide);
$('#sliderList').animate({ left: "+=400px" }, "slow", "swing");
clearInterval(myTimer);
myTimer = setInterval(slide, 2000);
}
else {
$('#sliderList').animate({ left: "+=400" }, "slow", "swing");
clearInterval(myTimer);
myTimer = setInterval(slide, 2000);
}
blockedSlider = false;
}
});
});
And my HTML:
<div id="sliderOuterWrapper">
<div id="sliderWrapper">
<a id="sliderLeft" ><</a>
<a id="sliderRight" >></a>
<ul id="sliderList">
<li class="sliderItem first">
<div><img src="" /></div>
</li>
<li class="sliderItem second">
<div><img src="" /></div>
</li>
<li class="sliderItem third">
<div><img src="" /></div>
</li>
<li class="sliderItem fourth">
<div><img src="" /></div>
</li>
<li class="sliderItem fifth">
<div><img src="" /></div>
</li>
</ul>
</div>
</div>
CSS:
* { margin: 0; padding: 0; }
#sliderWrapper { width: 400px; height: 350px; overflow: hidden; position:relative;}
#sliderList { list-style: none; left: 0px; position:absolute; width:200000em;}
.sliderItem { float: left; background-color:black; width: 400px; height: 350px;}
.sliderItem.first { background-color:red; }
.sliderItem.second { background-color:blue; }
.sliderItem.third { background-color:yellow; }
.sliderItem.fourth { background-color:green; }
#sliderLeft { position: absolute; font-size: 63px; top:39%; z-index: 10;}
#sliderRight { position: absolute; font-size: 63px; top:39%; z-index: 10; right: 0px;}
#sliderLeft:hover,
#sliderRight:hover { cursor: pointer; }
How can I stop these events from firing if a current animation is already taking place?
Please set back blockSlider to false in teh animate function call back
$('#sliderLeft').click(function () {
if (blockedSlider == false) {
blockedSlider = true;
var left = $('#sliderList').css('left');
left = left.substring(0, left.length - 2);
if (left <= -800) {
$('#sliderList').css('left', '-400px');
var slide = $('#sliderList li:first');
$('#sliderList').children('li:first').remove();
$('#sliderList').append(slide);
$('#sliderList').animate({ left: "-=400px" }, "slow", "swing",function(){
blockedSlider = false
});
clearInterval(myTimer);
myTimer = setInterval(slide, 2000);
}
else {
$('#sliderList').animate({ left: "-=400" }, "slow", "swing",function(){
blockedSlider = false
});
clearInterval(myTimer);
myTimer = setInterval(slide, 2000);
}
}
});

Categories