jQuery toggle Class on multiple Elements with interval - javascript

I've created this little fancy jQuery Snippet to toggle the class of an element in an interval:
setInterval(function(){$('.grid-item .slide-image').toggleClass('active')}, 800);
The script works fine! Now I got multiple elements with the base-class .slide-image in the wrapper .grid-item.
<div class="grid-item">
<div class="slide-image"><img src="http://www.placehold.it/500x500/233953"></div>
<div class="slide-image"><img src="http://www.placehold.it/500x500/03144b"></div>
<div class="slide-image"><img src="http://www.placehold.it/500x500/030a4b"></div>
</div>
Is there a way to rewrite the snippet so the second .slide-image gets the class .active after the first one? Then the third element and so on...
The Problem: The amout of .slide-image-elements is no defined. In some cases there are two of them, in another there are four elements.
Check out my CodePen!

Try this
var slides = $('.grid-item .slide-image'), // cache slides
counter = 0; // global counter
setInterval(function(){
slides.removeClass('active'); // remove active class
slides.eq(counter).addClass('active'); // add active class
counter++;
if (counter == slides.length) counter = 0; // reset counter after last slide
}, 800);
Updated CodePen

You can check if current active element id last or not. if it is, then show first element in set else show next sibling element:
$(function(){
var slides = $('.grid-item .slide-image');
setInterval(function(){
var currentactive = $('.active');
var _target = currentactive.is(':last-child') ? slides.first() : currentactive.next();
slides.removeClass('active')
_target.addClass('active')
}, 800);
});
Working Demo

Related

In pure JS, I am trying to set two similar classes but with different numbers or to set the same class to two different elemnts

I tried to set the same class imagens-giratorias to two elements or to set imagens-giratorias and imagens-giratorias-2. The class worked in first element, and the same class stopped of animating in the second element.
[I provide the JSFiddle at the end.]
Check the #rafaelcastrocouto's original code at https://stackoverflow.com/a/59524483/8041366. If you prefer reading the complete code here, here is the code taken from there, but with a bit modified:
var counter = 1;
var div = document.querySelector('.imagens-giratorias');
var imagens = document.querySelectorAll('.imagens-giratorias img');
var showNext = function () {
counter++;
if (counter > 3) counter = 1;
div.classList.remove('imagem1', 'imagem2', 'imagem3')
div.classList.add('imagem'+counter);
};
for (var img of imagens) {
img.addEventListener('animationend', showNext);
}
And small CSS snippet:
<div class="section-2">
<div class="item-2">
<div class="imagens-giratorias imagem1">
</div>
</div>
</div>
<div class="section-3">
<div class="item-2">
<div class="imagens-giratorias imagem1">
</div>
</div>
Or
<div class="section-3">
<div class="item-2">
<div class="imagens-giratorias-2 imagem1">
</div>
</div>
1st solution, that same original code above I am referring.
2nd solution:
var div = document.querySelector('.imagens-giratorias, .imagens-giratorias-2');
var imagens = document.querySelectorAll('.imagens-giratorias img, .imagens-giratorias-2 img');
3rd solution
var div = document.querySelector('[class^=imagens-giratorias]');
var imagens = document.querySelectorAll('[class^=imagens-giratorias] img');
4th solution
const contador = 1;
const div = document.querySelector('.imagens-giratorias');
const imagens = document.querySelectorAll('.imagens-giratorias img');
I also tried to use from multiple selectors with document.querySelectorAll. No luck.
But all these solutions did not work.
JSFiddle
Please pay attention to two elements. While one element will always animate, another will stop of animating.
https://jsfiddle.net/gusbemacbe/mbp84u6r/2/
If I understand you correctly you're trying to grab elements that have a class name starting with imagens-giratorias. If that's the case, use the ^ attribute selector as shown below:
document.querySelectorAll("[class^="imagens-giratorias"]")
Update:
Based on your update it appears that only one of your two divs' images is animating but in reality they're stacked on top of each of other. Feel free to use whatever layout method you want but for demonstration's sake I floated one left and the other right. Other that it was a matter of looping through your divs and assigning your function to their child images as so:
var divs = document.querySelectorAll('.imagens-giratórias');
var contador = 1;
var mostrarPróximo = function(div) {
contador++;
if (contador > 3) contador = 1;
div.classList.remove('imagem1', 'imagem2', 'imagem3')
div.classList.add('imagem' + contador);
};
Array.from(divs).forEach(function(div, index) {
var images = div.querySelectorAll('img');
Array.from(images).forEach(function(img) {
img.addEventListener('animationend', mostrarPróximo.bind(null, div));
});
});
https://jsfiddle.net/1r6yjf5s/

jQuery select DIV by class name starting from top

I have a structure like the following to create a one page web application, using some scroll functionalities:
<div class="home_section"></div> <!-- 1 -->
<div class="home_section"></div> <!-- 2 -->
<div class="home_section"></div> <!-- 3 -->
<div class="home_section"></div> <!-- 4 -->
I need to scroll to each of the above DIVs when the scroll event starts.
So, for example, when the scroll starts, if the first DIV visible from top is <!-- 2 -->, the body will have to scroll to the DIV <!-- 3 --> automatically.
This is what I am doing:
if ($(this).attr('id') == 'home') {
$(document).on("scrollstart", function (e) {
console.log('scrolling started on home');
e.preventDefault();
var next = $(this).find(".home_section"); //here I need to calculate which is the next DIV to scroll to
$('html, body').animate({
scrollTop: next.offset().top
});
});
}
The problem is that I do not know how to check which is the first .home_section DIV visibile starting from top, so I am unable to calculate which is the next target DIV to scroll to.
Thanks for ay help
I would loop through all the .home_sections divs, and get the first :visible like this
var divs = $(".home_section");
for(var x = 0; x < divs.length; x++){
if($(divs[x]).is(":visible")){
//do what you need here
var me = divs[x];
var next = x < divs.length - 1 ? divs[x] : undefined;
if(next){
//do the scroll
}
//then break the for loop
break;
}
}
This way you have an array of divs, you find the first visible and then you have the reference to the nth+1 div.
Another solution that should work:
var firstVisible = $(".home_section:visible:eq(0)");
var next = $(firstVisible).next();
hope this helps
next div would be $(this).next();
var next = $(this).next();
But you would need to modify this line for it to work for all divs:
if ($(this).attr('id') == 'home')
Modify the line var next = $(this).find(".home_section"); as below to get first div with class "home_section".
var next = $(this).getElementsByClassName("home_section")[0];

first time my function runs fine, second time its wrong jquery

I'm trying to make a lightbox. But when i open the lightbox for the second time. It goes trough my code twice. When i open my lightbox the third time, it goes trough my code three times. Don't get it at all.
$(document).ready(function(){
$('.bg-overlay, .overlay-content, .overlay-content img').hide();
$('.thump-bnr > li').click(function(){
// show the overlay and bg-overlay
$('.bg-overlay, .overlay-content').fadeIn(500);
// gets the index of the thunp thats been clicked in the banner
var x = $(this).index();
// console.log(x);
$('.overlay-content > img').eq(x).fadeIn(500);
// thumpPop checks if there aren't to mutch list items
var thumpPop = $('.overlay-content .thump-pop li').length;
// console.log(thumpPop);
// appends all li for the thump navigation in the overlay
if (thumpPop < 1) {
$('.overlay-content').append('<ul class="thump-pop"></ul>');
for (var i = 0; i < 4; i++) {
$('.thump-pop').append('<li></li>');
}
}
// sets all thump li to the border white
$('.thump-pop > li').css("border-color", "#fff");
// sets the active thump li to a dark border
$('.thump-pop > li').eq(x).css("border-color", "#e2e2e2");
// console.log(x);
// calls the thumpNav function for the thump navigation
thumpNav();
// calles the arrowNav function for the arrow navigation beside the big images
arrowNav();
});
In this function i have managed to execute the function only once by using an if statement.
// this is the function for the thump navigation
function thumpNav() {
$('.thump-pop > li').click(function(){
// get the index number of the thump li
var y = $(this).index();
// console.log(y);
// checks if the big image thats equal to the clicked thump is hidden
if($('.overlay-content > img').eq(y).is(':hidden')) {
// fadeIn and fadeOut the big images
$('.overlay-content img').fadeOut();
$('.overlay-content > img').eq(y).fadeIn();
// this wil change the border color of the active li
$('.thump-pop > li').css("border-color", "#fff");
$(this).css("border-color", "#e2e2e2");
}
});
}
I think i have made a mistake in the function arrowNav(), because he executes this twice when i open my lightbox for the second time.
function arrowNav() {
$('.arrow-nav-left').click(function(){
// this wil get the index number of the visible image in the overlay. This number can be used to display the number -1 our +1
var x = $('.overlay-content').find('img:visible').index();
// console.log(x);
var x = x - 2;
console.log(x);
$('.overlay-content > img').hide();
$('.overlay-content > img').eq(x).show();
});
}
// hides the pop-up
$('.bg-overlay').click(function(){
$('.bg-overlay, .overlay-content, .overlay-content img').fadeOut(500);
});
});
Please help me, and some feedback on the code is alway helpfull. Thanks
The problem is here:
function thumpNav() {
$('.thump-pop > li').click(function(){
You're attaching a new click handler everytime you call thumpNav, and they will all execute and do the same thing everytime you click.
Replace with:
function thumpNav() {
$('.thump-pop > li').unbind("click").click(function(){
Just like you did with arrowNav().
Note that your code is very unefficient and not structured quite right. Even if this works it's not good when you're juggling click handlers like this. At least define the callback as a seperate function and pass that as an argument to click().
If you want to get help with improving your code, you can always post it on Codereview.
Every time you're calling:
thumpNav();
you're attaching a new click handler.
same with arrowNav()
but atleast here you unbind first.

How to reduce 180 lines of code down to 20 in Javascript?

I have a lot of click handler functions which are almost (textually and functionally) identical. I've got a menu with maybe 10 items in it; when I click on an item, the click handler simply makes one div visible, and the other 9 div's hidden. Maintaining this is difficult, and I just know there's got to be a smart and/or incomprehensible way to reduce code bloat here. Any ideas how? jQuery is Ok. The code at the moment is:
// repeat this function 10 times, once for each menu item
$(function() {
$('#menuItem0').click(function(e) {
// set 9 divs hidden, 1 visble
setItem1DivVisible(false);
// ...repeat for 2 through 9, and then
setItem0DivVisible(true);
});
});
// repeat this function 10 times, once for each div
function setItem0DivVisible(on) {
var ele = document.getElementById("Item0Div");
ele.style.display = on? "block" : "none";
}
Create 10 div with a class for marking
<div id="id1" class="Testing">....</div>
<div id="id2" class="Testing">....</div>
<div id="id3" class="Testing">....</div>
and apply the code
$('.Testing').each(function() {
$(this).click(function() {
$('.Testing').css('display', 'none');
$(this).css('display', 'block');
}
}
$(document).ready(function (){
$("div").click(function(){
// I am using background-color here, because if I use display:none; I won't
// be able to show the effect; they will all disappear
$(this).css("background-color","red");
$(this).siblings().css("background-color", "none");
});
});
Use .siblings() and it makes everything easy. Use it for your menu items with appropriate IDs. This works without any for loops or extra classes/markup in your code. And will work even if you add more divs.
Demo
Fiddle - http://jsfiddle.net/9XSJW/1/
It's hard to know without an example of the html. Assuming that there is no way to traverse from the menuItem to ItemDiv - you could use .index and .eq to match up the elements based on the order they match with the selector.
var $menuItems = $("#menuItem0, #menuItem1, #menuItem2, ...");
var $divs = $("#Item0Div, #Item1Div, #Item2Div, ...");
$menuItems.click(function(){
var idx = $(this).index();
// hide all the divs
$divs.hide()
// show the one matching the index
.eq(idx).show();
})
Try
function addClick(i) {
$('#menuItem'+i).click(function(e) {
// set nine divs hidden, 1 visble
for( var j = 0; j < 10; ++j ) {
var ele = document.getElementById("Item"+j+"Div");
ele.style.display = (i == j ? "block" : "none");
}
});
}
// One click function for all menuItem/n/ elements
$('[id^="menuItem"]').on('click', function() {
var id = this.id; // Get the ID of the clicked element
$('[id^="Item"][id$="Div"]').hide(); // Hide all Item/n/Div elements
$('#Item' + id + 'Div').show(); // Show Item/n/Div related to clicked element
});
Obviously this would be much more logical if you were using classes instead:
<elem class="menuItem" data-rel="ItemDiv-1">...</elem>
...
<elem class="ItemDiv" id="ItemDiv-1">...</elem>
$('.menuItem').on('click', function() {
var rel = $(this).data('rel'); // Get related ItemDiv ID
$('.ItemDiv').hide(); // Hide all ItemDiv elements
$('#' + rel).show(); // Show ItemDiv related to clicked element
});
Save the relevant Id's in an array - ["Item0Div", "Item1Div", ...]
Create a generic setItemDivVisible method:
function setItemDivVisible(visible, id) {
var ele = document.getElementById(id);
ele.style.display = visible ? "block" : "none";
}
And set your click handler method to be:
function(e) {
var arrayLength = myStringArray.length;
for (var i = 0; i < idsArray.length; i++) {
setItemDivVisible(idsArray[i] === this.id, idsArray[i]);
}
}
I think this will do the trick

Get next element after the active

how to get the next dt after the dt with class active?
my HTML::
<dt class="active">...</dt>
<dd>...</dd>
<dt>...</dt>
<dd>...</dd>
<dt>...</dt>
<dd>...</dd>
look, i have this function:
function slideShow() {
var active = $('dl dt.active',ctx);
active.next('dt').addClass('active');
};
window.setInterval(slideShow, 5000);
should be simple. every sec the DOM show where the active dt is and set the next dt of this active.
One possible solution is
$('.active').nextUntil('dt').last().next()
Demo: Fiddle
For the slide show
var $dts = $('dl dt');
function slideShow() {
var index = $dts.index($dts.filter('.active').removeClass('active')) + 1;
var active = $dts.eq(index > 0 && index < $dts.length ? index : 0);
active.addClass('active');
};
window.setInterval(slideShow, 1000);
Demo: Fiddle
Its not so simple, you can use the next sibling selector ~ in combination with eq() to select the element:
$(".active ~dt:eq(0)")
JS Fiddle: http://jsfiddle.net/hsAA7/

Categories

Resources