I have written a custom slider with object-oriented javascript as seen below. I have included the module in a fiddle here https://jsfiddle.net/5z29xhzg/7/. After sliding left or right, the slides are cloned and appended accordingly so that the user can loop through the slider as much as wanted. There is a separate function for controlling the active tab. When used separately, the tabs and slider work perfectly, but I am having an issue when the two are used in conjuction. For instance, clicking 'blue apron' and then clicking the left slide button (which should take you to the 'dave & busters' slide) takes you to the bliss slide. Or clicking the last slide using the tabs and then clicking the next button does not show anything. Can someone point out the flaw in the object that I have written. Any help is much appreciated!
GiftSlider = {
prev: '.slider-container .prev',
next: '.slider-container .next',
slide: '.slide',
slidesContainer: '#slides',
navLink: '.gift-nav li a',
init: function() {
// Initialize nextSlide function when clicking right arrow
$(this.next).click(this.nextSlide.bind(this));
$(this.next).click(this.activeTabs.bind(this));
// Initialize prevSlide function when clicking left arrow
$(this.prev).click(this.prevSlide.bind(this));
$(this.prev).click(this.activeTabs.bind(this));
// Initialize toggleSlides and activeTab functions when clicking nav links
$(this.navLink).click(this.toggleSlides.bind(this));
$(this.navLink).click(this.activeTabs.bind(this));
},
nextSlide: function(e) {
// Prevent default anchor click
e.preventDefault();
// Set the current slide
var currentSlide = $('.slide.current');
// Set the next slide
var nextSlide = $('.slide.current').next();
// remove the current class from the current slide
currentSlide.removeClass("current");
// Move the current slide to the end so we can cycle through
currentSlide.clone().appendTo(this.slidesContainer);
// remove the last slide so there is not two instances
currentSlide.remove();
// Add current class to next slide to display it
nextSlide.addClass("current");
},
prevSlide: function(e) {
// Prevent defaulct anchor click
e.preventDefault();
// Set the current slide
var currentSlide = $('.slide.current');
// Set the last slide
var lastSlide = $('.slide').last();
// remove the current class from the current slide
currentSlide.removeClass("current");
// Move the last slide to the beginning so we can cycle through
lastSlide.clone().prependTo(this.slidesContainer);
// remove the last slide so there is not two instances
lastSlide.remove();
// Add current class to new first slide
$('.slide').first().addClass("current");
},
toggleSlides: function(e) {
// Prevent defaulct anchor click
e.preventDefault();
var itemData = e.currentTarget.dataset.index;
var currentSlide = $('.slide.current');
currentSlide.removeClass("current");
newSlide = $('#slide-' + itemData);
// currentSlide.clone().appendTo(this.slidesContainer);
newSlide.addClass("current");
// console.log(newSlide);
},
activeTabs: function() {
// *** This could be much simpler if we didnt need to match the slider buttons
// *** up with nav tabs. Because I need to track the slider as well, I have
// *** made this its own function to be used in both instances
// get the active slide
var activeSlide = $('.slide').filter(':visible');
// get the active slide's id
var currentId = activeSlide.attr('id');
// grab just the number from the active slide's id
var currentNum = currentId.slice(-1);
// remove any active gift-nav links
$(this.navLink).removeClass("active");
// get the current tab by matching it to the current slide's id
var currentTab = $('.gift-nav li a[data-index="' + currentNum + '"]');
// make that active
currentTab.addClass("active");
}
}
$(document).ready(function(){
// Init our objects
GiftSlider.init();
});
The bug seems to be in toggleSlides.
EDIT: The following doesn't work
When the page loads, currentSlide is slide 1. Now say you click the 3rd tab. At this point, you need to move the slide before the 3rd tab i.e. the 2nd tab to the end. When you say currentSlide.clone().appendTo(this.slidesContainer);, you are instead moving the first slide to the end. Therefore no matter which tab you clicked, when you click the previous button it was going to the first slide.
If instead you do newSlide.prev().clone().appendTo(this.slidesContainer); the code seems to work fine.
toggleSlides: function(e) {
// Prevent defaulct anchor click
e.preventDefault();
var itemData = e.currentTarget.dataset.index;
var currentSlide = $('.slide.current');
currentSlide.removeClass("current");
newSlide = $('#slide-' + itemData);
//currentSlide.clone().appendTo(this.slidesContainer);
newSlide.prev().clone().appendTo(this.slidesContainer);
newSlide.addClass("current");
//console.log("In toggle slide: "+newSlide.next().attr("id"));
//console.log("In toggle slide: "+newSlide.prev().attr("id"));
//console.log("In toggle slide: "+$('.slide.current').next().attr("id"));
},
This seems to work. Check it out at https://jsfiddle.net/rfgnm992/1/. Your nextSlide and previousSlide seems to keep the current slide at the beginning. toggleSlides wasn't doing that.
toggleSlides: function(e) {
// Prevent defaulct anchor click
e.preventDefault();
var itemData = e.currentTarget.dataset.index;
var currentSlide = $('.slide.current');
currentSlide.removeClass("current");
newSlide = $('#slide-' + itemData);
//keep new slide at the beginning and move the preceding slides to the end
newSlide.nextAll().addBack().prependTo(this.slidesContainer);
//console.log("NewSlide.next: "+newSlide.next().attr('id') + "NewSlide.next.next: "+newSlide.next().next().attr('id')+"newSlide.next.next.next: "+newSlide.next().next().next().attr('id'));
//currentSlide.clone().appendTo(this.slidesContainer);
newSlide.addClass("current");
// console.log(newSlide);
},
sorry I got back a bit later than expected. Took a look there. Think you're over-complicating things with the whole append/prepend/cloning thing.
I got it working, but there's a minor bug in it still. It cycles grand, forward and back and the correct links highlight, however when you click on a random link it doesn't immediately highlight, but when you click the next/prev buttons, the relevant links from the chosen image highlight. It's certainly an advance!!! I'm sure I could roll it out with another look, but its 2am here, and I've already been looking at it for an hour and a half!
Here's a fiddle and a snippet (just js cos my msg was too long - I just took out the paragraph at the end of the content, no css changes)
GiftSlider = {
prev: '.slider-container .prev',
next: '.slider-container .next',
slide: '.slide',
slidesContainer: '#slides',
navLink: '.gift-nav li a',
init: function() {
// Initialize nextSlide function when clicking right arrow
$(this.next).click(this.nextSlide.bind(this));
$(this.next).click(this.activeTabs.bind(this));
// Initialize prevSlide function when clicking left arrow
$(this.prev).click(this.prevSlide.bind(this));
$(this.prev).click(this.activeTabs.bind(this));
// Initialize toggleSlides and activeTab functions when clicking nav links
$(this.navLink).click(this.activeTabs.bind(this));
$(this.navLink).click(this.toggleSlides.bind(this));
},
nextSlide: function(e) {
// Prevent default anchor click
e.preventDefault();
// Set the current slide
var currentSlide = $('.slide.current');
// Set the next slide
var currentId = currentSlide.attr('id');
var currNum = (currentId.slice(-1));
var nextNum;
var increment = 1;
if (currNum == 4){
nextNum = 1;
}
else
{
nextNum = parseInt(currNum) + parseInt(increment) ;
}
var nextSlide = $('#slide-' + nextNum);
// remove the current class from the current slide
currentSlide.removeClass("current");
// Add current class to next slide to display it
nextSlide.addClass("current");
// remove the last slide so there is not two instances
},
prevSlide: function(e) {
// Prevent default anchor click
e.preventDefault();
// Set the current slide
var currentSlide = $('.slide.current');
// Set the last slide
var currentId = currentSlide.attr('id');
var currNum = (currentId.slice(-1));
var prevNum;
var decrement =1;
if (currNum == 1){
prevNum = 4;
}
else
{
prevNum = parseInt(currNum) - parseInt(decrement) ;
}
var prevSlide = $('#slide-' + prevNum);
// Move the last slide to the beginning so we can cycle through
currentSlide.removeClass("current");
// Add current class to new first slide
prevSlide.addClass("current");
},
toggleSlides: function(e) {
// Prevent defaulct anchor click
e.preventDefault();
var itemData = e.currentTarget.dataset.index;
var currentSlide = $('.slide.current');
currentSlide.removeClass("current");
newSlide = $('#slide-' + itemData);
newSlide.addClass("current");
},
activeTabs: function() {
var activeSlide = $('.slide').filter('.current');
// get the active slide's id
var currentId = activeSlide.attr('id');
// grab just the number from the active slide's id
var currentNum = currentId.slice(-1);
// remove any active gift-nav links
$(this.navLink).removeClass("active");
// get the current tab by matching it to the current slide's id
var currentTab = $('.gift-nav li a[data-index="'+ currentNum + '"]');
// make that active
currentTab.addClass("active");
}
}
$(document).ready(function(){
// Init our objects
GiftSlider.init();
});
Related
What I want to do is that when my question has a timer and the user next, that question disappears and I can not answer it.
Code:
var timer = $(".active").attr('data-timer');
if (timer == undefined) {
var $carousel = $('#carousel');
var NextElement = $carousel.next('.item').first();
NextElement.addClass('active');
$('.timer').remove();
} else {
var $carousel = $('#carousel');
var ActiveElement = $carousel.find('.item.active');
ActiveElement.remove();
var NextElement = $carousel.next('.item');
NextElement.addClass('active');
$('.timer').remove();
}
It does everything, except that when it enters the else instead of adding the active in my carousel it adds the class next left.
Instead of this class being added, it should be active, so when it re-enters the if the slide does not work anymore. Even add the following:
var NextElement = $carousel.next('.item').first();
It's the .first
Just use var NextElement = $carousel.next('.item'), next only returns one element https://api.jquery.com/next/
function nextSlideFunc() {
var currentSlide = $(".slide.active-slide");
var currentSlideIndex = $(".slide.active-slide").index();
var nextSlideIndex = currentSlideIndex + 1;
var nextSlide = $(".slide").eq(nextSlideIndex);
$("#nextBtn").on("click", function(e) {
e.preventDefault();
currentSlide.removeClass("active-slide");
if(nextSlideIndex === $(".slide").last().index() + 1) {
//stay at last slide when reached.
$(".slide").eq(nextSlideIndex - 1).addClass("active-slide");
} else {
nextSlide.addClass("active-slide");
}
});
}
After I clicked on the next button, the slide goes to the next slide which is what I want, but when I continue to click, it just stopped going forward.
I checked my HTML in the dev tool, it has the class name "active-slide" on one of the slides which fulfills the condition, but I'm not sure why it's not working.
As for the previous button, it's not removing class "active-slide" like it's supposed to, any idea why this is happening?
You have to set your variables inside the listener of your click event:
https://codepen.io/anon/pen/OxMxwd
$("#prevBtn").on("click", function(e) {
var currentSlide = $(".slide.active-slide");
var currentSlideIndex = $(".slide.active-slide").index();
var prevSlideIndex = currentSlideIndex - 1;
var prevSlide = $(".slide").eq(prevSlideIndex);
}
That way you will calculate your index and next index every time you click the button. The way you did it, is calculating it once and reusing it over and over again, so you will do the same thing on the same index over and over again.
I have the following jQuery or a carousel which I have pieced together.
The jQuery works fine locally - but when uploaded to a Drupal platform the jQuery no longer works. It will however work when input through the Console.
jQuery:
carousel = (function(){
// Read necessary elements from the DOM once
var box = document.querySelector('.carouselbox');
var next = box.querySelector('.next');
var prev = box.querySelector('.prev');
// Define the global counter, the items and the
// current item
var counter = 0;
var items = box.querySelectorAll('.content-items li');
var amount = items.length;
var current = items[0];
box.classList.add('active');
// navigate through the carousel
function navigate(direction) {
// hide the old current list item
current.classList.remove('current');
// calculate th new position
counter = counter + direction;
// if the previous one was chosen
// and the counter is less than 0
// make the counter the last element,
// thus looping the carousel
if (direction === -1 &&
counter < 0) {
counter = amount - 1;
}
// if the next button was clicked and there
// is no items element, set the counter
// to 0
if (direction === 1 &&
!items[counter]) {
counter = 0;
}
// set new current element
// and add CSS class
current = items[counter];
current.classList.add('current');
}
// add event handlers to buttons
next.addEventListener('click', function(ev) {
navigate(1);
});
prev.addEventListener('click', function(ev) {
navigate(-1);
});
// show the first element
// (when direction is 0 counter doesn't change)
navigate(0);
})();
Removed it from inline to its own js file - sourced the file - works perfectly
I am trying to create a simple jquery slideshow. However I am having trouble getting it to loop through the elements.
I know next() just add's the active class to the next elements, and not a single. That is the part i am having trouble with. How can just apply a single class to the next element, and it loop forever.
jQuery(document).ready(function () {
var slides = jQuery('#slideshow'); //Parent container for the slideshow
var activeClass = 'active'; //Set the active slide CSS class
var interval = 3000; // Interval in miliseconds
var countSlides = slides.children().length;
//Runs the slideshow
function cycle() {
slides.children().removeClass(activeClass);
slides.children().next().addClass(activeClass);
};
setInterval(cycle, interval);
});
According to the documentation .next() returns the element next to every element in the collection it is called on. In your case that is all children. If you select only the current active element before dropping the .active class you can get the element next to it.
function cycle() {
var $current = slides.children('.active');
$current
.removeClass('active')
.next().addClass('active');
}
Edit: as on how to loop. You need to check if there is a next element. If .next() does not return a new element you could grab the first child instead:
var $current = slides.children('.active'),
$next = $current.next();
if (!$next.length) {
// No next slide, go back to the first one.
$next = slides.children().first();
}
$current.removeClass('active');
$next.addClass('active');
I'm finding myself in a problem which I think has a easy solution but I cannot see... I have two functions to add a class called selected which highlights the buttons.
One function removes the class selected if present and adds the class to the button clicked:
var sidebarLinks = $('.js-sidebar a');
// About section: Remove and add class on click
sidebarLinks.on('click', function() {
sidebarLinks.removeClass('selected');
$(this).addClass('selected');
});
The other function adds the class selected if the user decides to scroll instead of clicking on the buttons. These buttons would highlight in a determined offset of the page:
var buttonOne = $('.buttonOne');
var buttonTwo = $('.buttonTwo');
var buttonThree = $('.buttonThree');
// Select nav buttons if scrolling and not clicking the button
$(window).scroll(function () {
// About nav sidebar links
var buttonOne = $('.js-polspotten-sidebar');
var buttonTwo = $('.js-product-sidebar');
var buttonThree = $('.js-designers-sidebar');
// About sections top scroll position
var currentTopPosition = $(this).scrollTop();
var productsTopPosition = $('#products').offset().top;
var designersTopPosition = $('#designers').offset().top;
// polspotten selected depending on scroll position
if (currentTopPosition >= currentTopPosition && currentTopPosition < productsTopPosition) {
buttonOne.addClass('selected');
}
else{
buttonOne.removeClass('selected');
}
// products selected depending on scroll position
if (currentTopPosition >= productsTopPosition &&
currentTopPosition < designersTopPosition) {
buttonTwo.addClass('selected');
}
else{
buttonTwo.removeClass('selected');
}
// designers selected depending on scroll position
if (currentTopPosition >= designersTopPosition) {
buttonThree.addClass('selected');
}
else{
buttonThree.removeClass('selected');
}
});
The problem is that both interact at the same time as the click event creates scroll.
What I want is that if somebody clicks on the button the scroll function will not work. It will only work if the user scrolls himself.
Is this possible?