Here is my bit of JavaScript:
comDivs = document.getElementsByClassName('comDiv');
fillerRants = document.getElementsByClassName('filler2Rant');
for (let y = 0; y < comDivs.length; y++) {
$(comDivs[y]).delay(4000).fadeOut(400, function() {
$(fillerRants[y]).fadeOut(400);
});
$(comDivs[y + 1]).delay(350).fadeIn(400, function() {
$(fillerRants[y + 1]).fadeIn(400);
});
}
This is supposed to show every element of the comDiv class one at a time for four seconds, then fadeOut() the current element and fadeIn() the next element. For example, the first item would be the only one showing when the page loads. After four seconds, it fades out and the second element fades in. Prior to this loop running, all elements except the first one have been hidden. With the above code, when the page loads, for some reason ALL the elements show up, then fade out one at a time. I have tried multiple different solutions, but none of them worked. What is wrong? I will be happy to provide additional information if it is needed.
My goal:
To enable a user to load a template (which contains preset jquery, html and css) to allow them to click one of five dots to trigger an animation on an image.
My issue:
When I load more than one of these templates to my page, my animation value (margin-left in this case) applies double the number of times that there is an instance of this template on the page. If my template is loaded twice, the margin-left sets to a value, jumps to the correct value, then back before finally setting on the correct value. This means that if I was to add 10 instances to the page, it would take 20 times as long to get that last value.
Before testing I thought that my code would be ok, as due to the context and .once()function, I believed it would only fire once.
All html and CSS are functioning as expected, it's just the jQuery is an issue.
My code:
(function ($) {
Drupal.behaviors.click_the_dots = {
attach: function (context, settings) {
$('.wrapper_class', context).once('click_the_dots', function () {
// Prevent other buttons from being clickable until the
// previous animation is complete.
var animationDone = false;
function clickDots(dotNum) {
$('.dot_class_num_' + dotNum).click(function () {
// Setup context, to keep animations to the container in which the dots exist.
var findElem = $(this).parent().parent().parent().find('.inner_wrapper');
// Prevent other buttons from being clickable until the
// previous animation is complete.
if (animationDone === false) {
animationDone = true;
// Find the visible image.
var animatingImage = findElem.find('.dot_class_num_active');
// Find the image that will be animating in.
var thisImageAnim = findElem.find('.dot_num_img_src_' + dotNum);
if (animatingImage.is(thisImageAnim)) {
// Can't click on the same dot again, until another dot is clicked.
animationDone = false;
return;
} else {
// Animate out the already visible image.
// Remove the visible image class as it's going to be hidden.
findElem.find('.dot_class_num_active').removeClass('dot_class_num_active');
// Animate it to hide to the left.
animatingImage.animate({
marginLeft: '-10%',
opacity: 0
}, 280, 'easeInOutQuad');
// Animate in the image associated with the dot click
// Set the image css to be further right in order to animate to left at 0.
thisImageAnim.css('margin-left', '10%').delay(200).animate({
marginLeft: '0',
opacity: 1
}, 300, 'easeInOutQuad', function () {
// Set the now visible image to the visible image.
thisImageAnim.addClass('dot_class_num_active');
}).promise().done(function () {
// Now allow the other dots to be clicked.
animationDone = false;
});
}
}
});
}
// For each of the five dots.
for (i = 1; i <= 5; i++) {
clickDots(i);
}
});}};})(jQuery);
I would like to add as many instances of this jQuery as required, but only have the function be looped through once. I'm not sure how to check if this has already been done, or how to ensure that once it has been done at least once, it shouldn't happen again.
:)
I figured out what my issue was - I was attaching the behaviour to the wrapper class of my content, i.e. $('.wrapper_class', context).once... - this meant that it attached the behaviour to each instance of this class, of which there could be many.
What I did was attach the behaviour to a higher parent element, of which I knew there would be only one instance. It attaches just once and the code works perfectly.
Thanks to the commenters above who helped me realise my issue!
I've got a container that includes several icons the user can hover over and be shown a block of text next to it. I'm grabbing the blocks of text from an array and have a randomize function so that they're always shown a different block of text when revisiting the page.
I ran into an issue where every time you hover over an icon, it keeps adding more array elements, because the function gets called each time you hover over the icon. So I decided to use the one() method so the function only runs once, however that's where my real issue is. Using the one() method doesn't show ANY text, and I'm pretty sure it's due to the nested function I have.
You can test this out here: http://www.evanvolmering.com/bootstrap/docs/examples/carousel/eyeswideshut.html
In the banner a video will play, and shortly into it a little icon will appear in the bottom of left of the banner. Hovering over it will show some text. When you hover over it again it adds another array item, and so on. It works, but I don't want it to keep adding array items.
10 seconds later another icon will appear to the top right, which currently has the one() method applied to it. As you can see nothing happens when you hover over it. Not sure where to go from here.
My randomize code (which I got from another StackOverflow answer):
var numRandoms = 14;
function makeUniqueRandom() {
if (!uniqueRandoms.length) {
for (var i = 0; i < numRandoms; i++) {
uniqueRandoms.push(i);
}
}
var index = Math.floor(Math.random() * uniqueRandoms.length);
var val = uniqueRandoms[index];
uniqueRandoms.splice(index, 1);
return val;
}
My code which currently 'works' but keeps adding more array items on hover:
$('img.button1').hover(function(){
$('p.trivia1').fadeIn("slow");
$( 'p.trivia1' ).append(makeUniqueRandom());
},
function(){
$("p.trivia1").stop().fadeOut("slow");
});
My code that uses one() but doesn't do anything on hover:
$('img.button2').one("hover",function(){
$('p.trivia2').fadeIn("slow");
$( 'p.trivia2' ).append(makeUniqueRandom());
},
function(){
$("p.trivia2").stop().fadeOut("slow");
});
Use mouseenter/mouseleave instead of hover
$('img.button1').on('mouseenter',function(){
$('p.trivia1').fadeIn("slow");
$( 'p.trivia1' ).append(makeUniqueRandom());
}).on('mouseleave',function(){
$("p.trivia1").stop().fadeOut("slow");
});
So I'm building this modal / timed animation with slide navigation from scratch.
I have a function for the buttons that navigate the slides, and also a function to animate the frames every 5 secs. My problem is I'm not sure how to "break" the delay function if the user decides to take over by clicking the navigation buttons. As soon as the user clicks any of those buttons the delay based animation function needs to stop working.
// Timer for Animating Frames
// Need a kill timer function
var animateFramesTimer = function(){
$('#tour_1')
.delay(5000).fadeOut('fast', function() {
$('#tour_2')
.fadeIn('fade').delay(5000).fadeOut('fast', function() {
$('#tour_3')
.fadeIn('fade').delay(5000).fadeOut('fast', function() {
$('#tour_4')
.fadeIn('fade').delay(5000).fadeOut('fast', function() {
$('#tour_modal').fadeOut('fast');
// END
});
});
});
});
}
animateFramesTimer();
So I run animateFramesTimer and if a certain button is clicked I need the function to stop working, I tried a while loop which seemed like the correct path to go, but it kept breaking in the browser :(
var autoAnimate = true;
while(autoAnimate){
// delay animation
}
Do you know of a better way to accomplish this?
$('[id^="tour_"]').stop(true, true); // kills current animations
animateFramesTimer = function() {}; // removes function
How can I reset the auto-scroll interval on my jCarouselLite carousel after some event so that it lets you look at the content for the full interval, regardless of how far along the timer was when you clicked next or previous? Right now, if I click next or previous after 9 seconds, it scrolls again after 1 second.
In the jCarouselLite source code on lines 274-277 is where the auto-scroll is implemented using setInterval. I know you can use clearInterval if you have the ID returned by setInterval, but there isn't one I can get outside of modifying the source code, and I don't want to do that.
Any ideas? Thanks!
jCarouselLite itself doesn't provide any easy way to stop the auto-scrolling, which is an easier problem then do what you seem to want (?did I understand this right: You just want the autoscroll to temporarily stop on click and then continue)
Hacky + potentially buggy way to stop the autoscroll altogether
var x; //hold interval id
$(function() {
var y = window.setInterval; //backup original setInterval function
//overwrite with new function which stores the id for us
window.setInterval = function() {
x = y(arguments[0], arguments[1]);
return x;
};
//now construct carousel
$(".anyClass").jCarouselLite({
btnNext: ".next",
btnPrev: ".prev",
auto: 500
});
//now restore original setInterval function
//as we only needed the custom one for the carousel to capture the hidden
//internal call to setInterval
window.setInterval = y;
});
$("#stopAutoScrollButton").click(function() {
clearInterval(x);
});
Real solution
As we can't get jCarouselLite to do this on its own we simulate the auto behavior ourself.
$(function() {
var autoTime = 5000; //5s
$(".anyClass").jCarouselLite({
btnNext: ".next",
btnPrev: ".prev"
});
//simulate autoscroll by simulating "click" on next link
var x = setInterval("$('.next').trigger('click');", autoTime);
//if stopAuto is clicked the autoscroll is suspended for autoTime
//no matter how far along the timer already was
$("#stopAuto").click(function() {
clearInterval(x);
x = setInterval("$('.next').trigger('click');", autoTime);
});
});
Here's a version with a pause on mouseover built-in. Works nicely.
http://github.com/cheald/jcarousel-lite
None of these answers were what I was looking for, but this is what comes up when I Google 'jcarousellite reset timer', so for the next person looking to:
Make the timer reset when you click your previous/next slide buttons
Pause the slideshow on hover
Then this is what I put together that works for me:
(function($){$.fn.jCarouselLite=function(o){o=$.extend({btnPrev:null,btnNext:null,btnGo:null,mouseWheel:false,auto:null,speed:200,easing:null,vertical:false,circular:true,visible:3,start:0,scroll:1,beforeStart:null,afterEnd:null},o||{});return this.each(function(){var running=false,animCss=o.vertical?"top":"left",sizeCss=o.vertical?"height":"width";var div=$(this),a=$("#featuredlistings a.next"),ul=$("ul",div),tLi=$("li",ul),tl=tLi.size(),v=o.visible;if(o.circular){ul.prepend(tLi.slice(tl-v-1+1).clone()).append(tLi.slice(0,v).clone());o.start+=v;}var li=$("li",ul),itemLength=li.size(),curr=o.start;div.css("visibility","visible");li.css({overflow:"hidden",float:o.vertical?"none":"left"});ul.css({margin:"0",padding:"0",position:"relative","list-style-type":"none","z-index":"1"});div.css({overflow:"hidden",position:"relative","z-index":"2",left:"0px"});var liSize=o.vertical?height(li):width(li);var ulSize=liSize*itemLength;var divSize=liSize*v;li.css({width:li.width(),height:li.height()});ul.css(sizeCss,ulSize+"px").css(animCss,-(curr*liSize));div.css(sizeCss,divSize+"px");if(o.btnPrev)$(o.btnPrev).click(function(){resetAuto(); return go(curr-o.scroll);});if(o.btnNext)$(o.btnNext).click(function(){resetAuto(); return go(curr+o.scroll);});if(o.btnGo)$.each(o.btnGo,function(i,val){$(val).click(function(){return go(o.circular?o.visible+i:i);});});if(o.mouseWheel&&div.mousewheel)div.mousewheel(function(e,d){return d>0?go(curr-o.scroll):go(curr+o.scroll);});if(o.auto){autoScroll=setInterval(function(){go(curr+o.scroll);},o.auto+o.speed);function resetAuto(){clearInterval(autoScroll);autoScroll=setInterval(function(){go(curr+o.scroll);},o.auto+o.speed);};div.hover(function(){clearInterval(autoScroll);},function(){autoScroll=setInterval(function(){go(curr+o.scroll);},o.auto+o.speed);});}function vis(){return li.slice(curr).slice(0,v);};function go(to){if(!running){if(o.beforeStart)o.beforeStart.call(this,vis());if(o.circular){if(to<=o.start-v-1){ul.css(animCss,-((itemLength-(v*2))*liSize)+"px");curr=to==o.start-v-1?itemLength-(v*2)-1:itemLength-(v*2)-o.scroll;}else if(to>=itemLength-v+1){ul.css(animCss,-((v)*liSize)+"px");curr=to==itemLength-v+1?v+1:v+o.scroll;}else curr=to;}else{if(to<0||to>itemLength-v)return;else curr=to;}running=true;ul.animate(animCss=="left"?{left:-(curr*liSize)}:{top:-(curr*liSize)},o.speed,o.easing,function(){if(o.afterEnd)o.afterEnd.call(this,vis());running=false;});if(!o.circular){$(o.btnPrev+","+o.btnNext).removeClass("disabled");$((curr-o.scroll<0&&o.btnPrev)||(curr+o.scroll>itemLength-v&&o.btnNext)||[]).addClass("disabled");}}return false;};});};function css(el,prop){return parseInt($.css(el[0],prop))||0;};function width(el){return el[0].offsetWidth+css(el,'marginLeft')+css(el,'marginRight');};function height(el){return el[0].offsetHeight+css(el,'marginTop')+css(el,'marginBottom');};})(jQuery);
Just swap it out with your current jCarouselLite script and use it just the same.
If you are able/authorized to change the plugin code:
Add a variable to save the interval id to the plugins defaults
interval: null
Search for:
if(o.auto)
Take the code which is executed here and make an internal function with it like:
function runAuto() {
setInterval(function() {
go(curr+o.scroll);
}, o.auto+o.speed);
}
Now just save the interval to your defined variable but clear it first:
function runAuto() {
clearInterval(o.interval);
o.interval = setInterval(function() {
go(curr+o.scroll);
}, o.auto+o.speed);
}
Search for the go() function in the plugin and add a runAuto(), so each time the function go is called it resets the interval.
Of course you must also add the runAuto() call to if(o.auto) so the interval starts at first.