I'm trying to set a loop on a slider but it would always stop on the last slider. Please help.
jsfiddle
function slideSwitch() {
var $active = $('div#slideshow .active');
var $next = $active.next();
$next.addClass('active');
$active.removeClass('active');
}
$(function() {
setInterval( "slideSwitch()", 5000 );
});
The problem is that you need to set $next to the first image when you reach the end. You can assume that if there is no $next elements, then it means that you need to start over from the beginning.
For example like this:
function slideSwitch() {
var $active = $('div#slideshow .active');
var $next = $active.next();
if (!$next.length) {
$next = $('div#slideshow > :first');
}
$next.addClass('active');
$active.removeClass('active');
}
$(function () {
setInterval(slideSwitch, 1000);
});
Unrelated, but instead of setInterval("slideSwitch()", 5000); pass function reference like in example above.
Demo: https://jsfiddle.net/na8zvhwh/2/
I would say that .next() make things needlessly complicated. This task is easily solved with some jQuery and a little math. Complete solution at the bottom, step-by-step with explanations following.
Pretty much only the internals of slideSwitch are changed. Requires that .active is set on one element. I like this solution because of its mathematical elegance, and because it's pretty easy to use once you understand the concept of it, and because it allows us to understand what we do instead of relying on things that "just work".
Step-by-step with explanation
What you want to do is get a list, iterate over it, change the class and then start from the beginning, right? A trick for this is using index % length.
Pretty much only the internals of slideSwitch are changed. Requires that .active is set on one element.
First, get the list of slides: (cache outside function for better performance)
var $list = $("div#slideshow");
Then, we want to find the active element and its index. This is done with:
var $current = $list.find(".active").index();
Then the magic. To find the next number, regardless of current position, we take $current, and add 1, then get the modulus (remained, essentially) of that number divided by the number of items total. The list of elements in #slideshow is returned by $list.children().
Thus, it will magically wrap around and start over when it reaches the end.
var $next = ($current + 1) % $list.children().length;
Then it's only a matter of removing the class from the current element and adding it to the next, using .get(index) which allows us to find() elements by their index and wrapping them in a jQuery object so we can use addClass() and removeClass(), because backwards compability.
$($list.children().get($current)).removeClass("active")
$($list.children().get($next)).addClass("active");
And that's it.
Full solution:
jsFiddle: http://jsfiddle.net/thn1vnmg/
function slideSwitch()
{
// Cache this outside function for performance
var $list = $("div#slideshow"),
$current = $list.find(".active").index(),
$next = ($current+1) % $list.children().length;
$($list.children().get($current)).removeClass("active")
$($list.children().get($next)).addClass("active");
}
$(function() {
setInterval( slideSwitch, 1000 );
});
http://en.wikipedia.org/wiki/Modular_arithmetic
A simple script that I use is this.
var imageShown = 1;
var total = 7;
function pic() {
var image = document.getElementById('picture');
imageShown = imageShown + x;
if(imageShown > total){imageShown = 1;}
if(imageShown < 1){imageShown = total;}
picture.src = "Images/img"+ imageShown +".jpg";
}
window.setInterval(pic, 5000);
You will need to customize the variables as needed to make your script match. Before this will work the pictures need to be put in the sub folder Images with the name img1, img2, and so forth. I know this will work because I have created an image slider that runs through automatically. Reset Javascript Timer for Image Slider
Related
Im trying to create animation function where I click on lets say the last child in a list,
then I'll need to move all siblings one by one to the left. So it will go like a wave.
Example:
Click on child nr.4, sibling nr.1 starts to move to the left out of the screen, and with a short delay sibling nr.2 and so on follow after. So it will be like a wave effect.
I have created a JSFiddle: http://jsfiddle.net/10kjn00z/2/
$('#menu li').click(function(){
setVar(this);
$(this).siblings().animate({left: '-'+tWidth+'px'}, function() {
$(this).animate({top: '-'+onSet+'px'});
});
});
This fiddle is just a short snippet off my code, so there might be code thats isnt in use here. But I'll get the idea.
Thanks
You can use the setTimeout() function to achieve what you want.
Here's an example of how you can do it:
$('#menu li').click(function(){
var speed = 100;
setVar(this);
var siblings = $(this).siblings();
$.each( siblings, function(index,value){
setTimeout(function(){$(value).animate({left: '-'+tWidth+'px'});}, index*speed);
});
var current = this;
setTimeout(function(){$(current).animate({top: '-'+onSet+'px'})}, 400-speed+siblings.length*speed);
});
Check it out on jsFiddle
if all the elements to be shifted belong to the same parent:
$('menu li').click(function(event) {
var list = event.currentTarget.parentNode.children;
var i = list.length;
var timeout = 100
while (i--) {
setTimeout(function() {
$(list[i]).animate(/*logic here*/);
}, timeout);
timeout += 100;
}
})
This will iterate through all the children of the parent in reverse order and apply the animation. You can also tweak this to only call on certain siblings. If you want them to iterate in order, use the standard for loop instead of while. The value timeout corresponds to milliseconds of delay and you can adjust the initial and increment values to adjust the animation timing.
You can achieve that behaviour using jQuery.fn.delay, where the delay-time depends on the elements position in the siblings-list.
$('#menu li').click(function(){
setVar(this);
// call .each on siblings, because each will get a different delay
$(this).siblings().each(function(index, sibl) {
$(sibl).delay( index * 250 )
.animate({left: '-'+tWidth+'px'}, function() {
$(this).animate({top: '-'+onSet+'px'});
});
});
});
So this is a bit of a head scratcher and I've resorted to asking for help with it. I have created a series of functions with jQuery. Each function contains an animate() queue and ends with a call back that loads the next function, again with it's own animate() queue. Once it reaches the end it calls the first function again and around we go. I have separated the queues into independent functions, because I want to be able to jump to specific points in the loop based on user clicks. So in the code below the loop runs through once, but when it goes back to the beginning the show() and hide() bits don't appear to be doing anything. Any help with this is greatly appreciated!
var firstItem = jQuery('#vehicle-banner-one');
var firstThumb = jQuery('#thumb-one');
var secondItem = jQuery('#vehicle-banner-two');
var secondThumb = jQuery('#thumb-two');
var thirdItem = jQuery('#vehicle-banner-three');
var thirdThumb = jQuery('#thumb-three');
var nextItem = firstItem;
var nextThumb = firstThumb;
firstItem.hide();
secondItem.hide();
thirdItem.hide();
function leadIn(){
console.log('leadIn');
thirdItem.css({zIndex:8});
secondItem.css({zIndex:9});
firstItem.css({zIndex:10});
firstItem.fadeIn("slow", function(){ holdOne(); });
}
function holdOne(){
console.log('holdOne');
thirdItem.css({zIndex:8}).hide();
secondItem.css({zIndex:9}).hide();
firstItem.css({zIndex:10}).show();
firstItem.delay(3000).delay(0, function(){ transTwo(); });
};
function transTwo(){
console.log('transTwo');
thirdItem.css({zIndex:8}).hide();
secondItem.css({zIndex:10}).hide();
firstItem.css({zIndex:9}).show();
secondItem.fadeIn("slow" , function(){ holdTwo(); });
};
function holdTwo(){
console.log('holdTwo');
thirdItem.css({zIndex:8}).hide();
secondItem.css({zIndex:10}).show();
firstItem.css({zIndex:9}).hide();
secondItem.delay(3000).delay(0, function(){ transThree(); });
};
function transThree(){
console.log('transThree');
thirdItem.css({zIndex:10}).hide();
secondItem.css({zIndex:9}).show();
firstItem.css({zIndex:8}).hide();
thirdItem.fadeIn("slow" , function(){ holdThree(); });
};
function holdThree(){
console.log('holdThree');
thirdItem.css({zIndex:10}).show();
secondItem.css({zIndex:9}).hide();
firstItem.css({zIndex:8}).hide();
thirdItem.delay(3000).delay(0, function(){ transOne(); });
};
function transOne(){
console.log('transOne');
thirdItem.css({zIndex:9}).show();
secondItem.css({zIndex:8}).hide();
firstItem.css({zIndex:10}).hide();
firstItem.fadeIn("slow" , function(){ holdOne(); });
};
leadIn();
///toggle by clicking thumbnails
jQuery('#thumb-one').on('click', function(){console.log('1'); holdOne();});
jQuery('#thumb-two').on('click', function(){console.log('2'); holdTwo();});
jQuery('#thumb-three').on('click', function(){console.log('3'); holdThree();});
});
looks kinda complicated... all i understood was, that you are looking for a way to loop through a list of items AND interrupt the loop any time with a click and then start from there on...
i've needed something similar some time before... we start with the snippet from css-tricks.com
All he does, is using the setInterval function to cycle through the elements:
$("#slideshow > div:gt(0)").hide();
setInterval(function() {
$('#slideshow > div:first')
.fadeOut(1000)
.next()
.fadeIn(1000)
.end()
.appendTo('#slideshow');
}, 3000);
this is neat and nice. it shows the first element, fades it out, takes the next element, fades it in and finally appends the first element to the end of the list.
this means, that the visible element is always the first one and therefore good to address.
that was it from css-tricks ... now we are out on our own, and we do want to have a link list, to directly address the single slides... i choose to enumerate all my pages, so this was my solution:
for (i = 1; i <= $("#slides div").length; i++) {
var slideName = $("#slides div").eq(i - 1).attr("name");
$("#slideselect").append("<a href='#' class='singleSelect' name='" + slideName + "'>" + i + " </a>");
}
having a link-list, won't help, as long as you don't have a click function. since the links are inserted after document.ready, i had to use on("click", , function), to have the click handle available...
the function first of all finds the name of the clicked element and compares it to the current active element. in case they match, we won't do anything, since the clicked slide is already shown.
$("#slideselect").on("click", ".singleSelect", function () {
var clickedSlide = $(this).attr("name");
var activeSlide = $('#slides > .activeSlide').attr("name");
clearInterval(cycleHandle);
if (clickedSlide != activeSlide) {
then, because we don't want to destroy our ordered list, we loop through our elements always moving the first one to the last position, until we found our clicked element. afterwards, we fadeout the active slide and fade in the clicked one...
while (clickedSlide != $('#slides > div:first').attr("name")) {
$('#slides > div:first').appendTo('#slides');
}
$('#slides > .activeSlide').fadeOut(1000)
.removeClass("activeSlide").end();
$('#slides > div:first').fadeIn(1000)
.addClass("activeSlide")
.end();
}
cycleHandle = setInterval(function(){myCycle()}, 3000);
});
the code inside my post is already the finished version. what you may notice is the clearInterval and setInterval call... if you won't clear the interval, the clicked slide will correct fade in to display, but the interval keeps running with the old offset. e.g. if you click a page 1 sec before the interval-loop would move on, your clicked slide will be there for only 1sec...
so i took the css-trick snippet into my own cycle function, and call this once after document ready. and inside the click handle, you'll stop the interval and start it again...
well hope you understood my work... here's the fiddle: http://jsfiddle.net/sx1mozeg/2/
there is still strange behaviour with the transitions, if you spam your clicks... need to improve that ...
i'm building a webpage where many spanĀ needs to be transitioned from one class to another to create a bg-color fadein effect. Distribution of elements of same classes is mixed through the page, but they are all grouped under common classes.
I want to create a behavior that does the following: when you click any elements of class-n, the other elements of that class transitions, with the clicked element acting as the starting point.
This is mostly figured out, thanks to some help on SO; see the jsfiddle.
$(".div").click(function () {
var itemClasses = this.classList;
var itemThread = itemClasses[1];
colorThread($(this), itemThread);
console.log(itemThread);
});
function colorThread($div, tId) {
tId = '.'+tId;
$div.toggleClass('div-clicked');
setTimeout(function () {
(function togglePrev($div) {
$div.toggleClass('div-clicked');
setTimeout(function () {
togglePrev($div.prev(tId));
}, 100);
})($div.prev(tId));
(function toggleNext($div) {
$div.toggleClass('div-clicked');
setTimeout(function () {
toggleNext($div.next(tId));
}, 100);
})($div.next(tId));
}, 100);
}
However, I am still struggling around a particular issue: I don't want the transition to stop if if encounter different class, I just want it not to toggle and keep iterating. If the jsfiddle, that would translate in all of the same color div to transition, regardless of their placement in the DOM tree.
In my togglePrev/toggleNext function, I have tried something along
if($div.hasClass(".classToTransition"))
{
$div.toggleClass(".div-clicked");
}
but couldn't get it to work properly (it doesn't ieterate to the next elements). There is something that I can't seem to grasp in the structure of that conditional. Anyone has a lead?
You really did manage to complicate something that should be pretty simple ?
$(".div").click(function () {
var coll = $('.'+this.className.replace(/(div-clicked|div)/g, '').trim()),
idx = coll.index($(this).toggleClass('div-clicked'));
$.each(coll, function(i) {
setTimeout(function() {
if (idx + i <= coll.length) coll.eq(idx + i).toggleClass('div-clicked');
if (idx - i >= 0) coll.eq(idx - i).toggleClass('div-clicked');
},i*200);
});
});
FIDDLE
It gets all the elements with the same class as the one currently clicked, and the index of the currently clicked, and then just adds and subtract 1 to the current index to get the next and previous elements. The checks are to make sure it stops when it reaches the end.
I don't want the transition to stop if if encounter different class, I just want it not to toggle and keep iterating
You might want to use nextAll(tId).first()/prevAll(tId).first() to select the next to-be-toggled element: http://jsfiddle.net/35uNW/4/. .next() does only look at the next sibling, and if that doesn't match your tId selector, no element will be selected.
If you want to iterate the different-classed elements so that you wait for each one, but don't want to toggle it, you can use your if-condition but you must remove the tId selector from the next()/prev() calls: http://jsfiddle.net/35uNW/3/.
This was a fun one. I did it a slightly different way, getting all of the matched elements and splitting them into before and after arrays.
var $allItems = $(".div");
$(".div").click(function () {
var itemClasses = this.classList;
var itemThread = itemClasses[1];
colorThread($(this), itemThread);
});
function colorThread($div, classname) {
var tId = '.'+classname,
$divs = $allItems.filter(tId),
index = $divs.index($div),
$before = $divs.slice(0, index),
before = $before.get().reverse(),
$after = $divs.slice(index+1);
$div.toggleClass('div-clicked');
$(before).each(function(i, item){
setTimeout(function () {
$(item).toggleClass('div-clicked');
}, i*100);
});
$($after).each(function(i, item){
setTimeout(function () {
$(item).toggleClass('div-clicked');
}, i*100);
});
}
Here's a working fiddle: http://jsfiddle.net/5sUr4/
I have a little snippet I want to make into a function. But I'm new to javascript. Obviously there is something wrong with the way I pass variables or the way I call them...
So in nutshell, this works: http://jsfiddle.net/kkvbz/
But this doesn't: http://jsfiddle.net/PrtD4/
Problem is I need it as a function, so I've to make 1 version work.
Full snippet:
function cutandMakeslides (containerid,liperslide) {
//This is for footer slider, it rewrites 1 ul into several uls that contain 4 li max.
// get the container, useful for later too...
var container = $(containerid);
// get all available UL and LI elements...
var li_elements = container.find("> UL > LI").clone();
// remove the current content so that we can rebuild it for the slider...
container.find("> UL").remove();
// build the slider container...
var slide_container = $("<div />");
// tricky part: looping through the LI's and building each of the slides...
// first create some helpful variables...
var li_elements_per_slide = liperslide;
var li_counter = 0;
// create the first slide, with a UL to hold the LI's...
var current_li_div = $("<div />");
current_li_div.append($("<ul />"));
// loop through the LI's...
li_elements.each(function(index, element){
li_counter++;
var current_li = $(element).clone();
current_li_div.find("> UL").append(current_li);
if (li_counter % li_elements_per_slide == 0)
{
// we've hit 4 in this list, so add the slide and make
// a new one, using same code as before...
container.append(current_li_div);
current_li_div = $("<div />");
current_li_div.append($("<ul />"));
}
});
// we might have an uneven number of LI's, so we need to check for this...
if (li_counter % li_elements_per_slide != 0)
container.append(current_li_div);
} // end function cutandMakeslides
//activate function above
$(function() { cutandMakeslides(".fproductslides",3); });
Problematic parts:
function cutandMakeslides (containerid,liperslide) {
var container = $(containerid);
var li_elements_per_slide = liperslide;
}
$(function() { cutandMakeslides(".fproductslides",3); });
So after extensive testing and moving the code to a fiddle, the problem seems to have resolved itself during moving it to the fiddle, so we believe there was a minor spelling or syntax error...however using a code comparison tool I was unable to find anything...
none of the problematic parts seemed to have an error:
function cutandMakeslides (containerid,liperslide) {
var container = $(containerid);
var li_elements_per_slide = liperslide;
}
$(function() { cutandMakeslides(".fproductslides",3); });
Here's a copy of the working fiddle
From your 'problematic parts' section it appears you are trying to pass a class(".fproductslides" is a class, classes start with '.' and Id's start with '#') instead of an Id as your variable names lead me to believe you want to do...
Here's what should happen.
1. Get the rel attribute of the clicked link
2. For every div with class 'entry':
(i)Get its 'left' position
(ii) Calculate its outer height
(iii)Loop through all instances of 'a.tag_filter'. If it finds the same string in the 'rel' as the one oringinally clicked on then add 1 to 'V' and break out of the loop.
(iv)If 'V' is equal to 0 after the loop we know the same tag isn't present within that '.entry' so fade it out.
(v)Once the fadeout has finished loop through all the '.entry' after the faded out one and get their 'left' values.
(vi)If the left value of the faded entry = the left value of the current '.entry' then reposition it to the new 'top' value.
What is currently happening.
It runs through and fades out all the correct '.entry' elements and only after all of them have faded out does it reposition them remaining '.entry' elements.
After each element is faded out I would like the repositioning loop to run so it essentially positions the remaining elements one at a time rather than all at once.
Heres my code EDIT:
$('a.tag_filter').click(function(e){
e.preventDefault();
var selectTag = $(this).attr('rel');
$('div.spotlight_entry_container_grid').each(function(i){
var $entry = $(this);
var tagArray = [];
$('a.tag_filter', this).each(function(){
tagArray.push ($(this).attr('rel'));
});
if($.inArray(selectTag,tagArray) == -1){
var leftPos = $entry.css("left");
var topPos = $entry.css("top");
$entry.fadeOut(1000, function(){
var nextLeftPos;
var nextTopPos;
$('div.spotlight_entry_container_grid:gt('+i+')').each(function(j) {
var $laterEntry = $(this);
nextLeftPos = $laterEntry.css("left");
nextTopPos = $laterEntry.css("top");
//we need to keep the entries in their columns.
//matching left values will do it. No need to animate left values.
if(leftPos == nextLeftPos){
$laterEntry.animate({ top: topPos});
}
});
});
}
});
});
Hopefully that makes sense
Any help would be appreciated!
I'm probably doing something crazy but I just can't spot it.
Thanks
in here
$('a.tag_filter', this).each(function(){
var curTag = $(this).attr('rel');
if(curTag == selectTag){
v++;
return false;
}
});
returning false inside of $().each() breaks the looping through each element in the wrapped set.
From the documentation
Returning 'false' from within the each
function completely stops the loop
through all of the elements (this is
like using a 'break' with a normal
loop). Returning 'true' from within
the loop skips to the next iteration
(this is like using a 'continue' with
a normal loop).
Also, I would recommend caching $(this) inside of each each() in a local variable for performance instead of referencing it several times.
EDIT:
After looking at the code further, I think the following should do it
$('a.tag_filter').click(function(e){
// prevent the default anchor behaviour
e.preventDefault();
var selectTag = $(this).attr('rel');
$('div.entry').each(function(i){
var $entry = $(this);
// get an array of the anchor tag rel attributes
var tagArray = [];
$('a.tag_filter', this).each(function() {
tagArray.push ($(this).attr('rel'));
});
// if we can't find the selected tag in the entries tags
if ($.inArray(selectTag,tagArray) == -1) {
var leftPos = $entry.css("left");
var topPos = $entry.css("top");
$entry.fadeOut(1000, function(){
var nextLeftPos;
var nextTopPos;
$('div.entry:gt('+i+')').each(function(j) {
var $laterEntry = $(this);
nextLeftPos = $laterEntry.css("left");
nextTopPos = $laterEntry.css("top");
// for the first element, set top and left to the faded out element values
if (j == 0) {
$laterEntry.animate({ top: topPos, left: leftPos });
}
// for later elements in the loop, ste the values to the previous element values
else {
$laterEntry.animate({ top: nextTopPos, left: nextLeftPos });
}
});
});
}
});
});
You don't need to cache $(this), jQuery auto caches the this selector for function callbacks.