Click handler is called multiple times in jQuery animate - javascript

I am getting familiar with jQuery and making a little application where a red box moves around the screen and the user has to try and click on it and when the user does an alert() box pops up but the problem is that the alert() keeps popping up even after 'ok' is pressed. The only way I can stop it is to repeatedly click 'ok' and eventually it goes away.
Here is the code that displays the alert box:
function Animate() {
var _newPosition = GetNewPosition();
// Sets new position of div
div.animate({
top: _newPosition[0],
left: _newPosition[1]
}, function () {
div.on('click', function () {
alert('You clicked the box!');
});
Animate();
});
}
Here is my JSFiddle that reproduces the problem
I originally thought that I could solve it by returning false after the call to the alert() for example:
div.on('click', function () {
alert('You clicked the box!');
return false;
});
But that didn't work either.
I know this should be a simple thing to figure out but I cant quite seem to get my thumb on it.

The click handler is recursively called in the animation complete callback which is binding the click event on the element multiple times. So, when the element is clicked the handler is being called multiple times.
To solve the issue, bind the event only once.
function Animate() {
var _newPosition = GetNewPosition();
// Sets new position of div
div.animate({
top: _newPosition[0],
left: _newPosition[1]
}, Animate);
}
And in ready()
$(document).ready(function () {
Animate();
div.on('click', function() {
// Code here
alert('clicked');
});
});
Using Animate as reference to the animation complete callback is same as
function() {
Animate();
}
The function reference will be passed to the animate and it'll be called when the animation is completed.
Suggestions:
Use mousedown event to track the click on moving object
Use random duration for animate.
FIddle
var div = $('#box');
$(document).ready(function() {
Animate();
div.on('mousedown', function() {
// Code here
console.log('clicked');
});
});
function GetNewPosition() {
// Get dimentions of the window and remove the div area
var h = $(window).height() - 50;
var w = $(window).width() - 50;
// New height and width is auto generated
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh, nw];
}
function Animate() {
var _newPosition = GetNewPosition();
// Sets new position of div
div.animate({
top: _newPosition[0],
left: _newPosition[1]
}, (Math.floor(Math.random() * 5000) + 1), Animate);
}
#box {
width: 50px;
height: 50px;
background-color: red;
position: fixed;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3 id="success"></h3>
<div id="box"></div>

Event is getting bound multiple times as it is in animate function. Instead binding click event in animate bind it in $(document).ready(function () {}); so that it will only get bound once.
Please find updated jsfiddle

Related

Why does a simple click function not find the selector?

I am writing a really quick js module that opens up and image and fades out a container to show the image. The markup for the image is this below:
<div style="margin-bottom:1px;" class="rsNavItem rsThumb front">
<div class="rsTmb portfolio">
<img src="http://www.mysterium.ch/revelation/pictures/revelation_highres_06.jpg"/>
</div>
</div>
Now what happens is the click basically fades out a div and then shows the container.
loadSlide: function () {
console.log('clicked');
//$('.rsThumb').each(function () {
var containerT = $('.rsnav-container'),
containerB = containerT.find('.rsThumb');
$('.rsThumb').click(function (e) {
console.log('clicked again');
e.preventDefault();
var sliderObject = $('.collection #gallery-t-group').data('royalSlider');
var s = this;
// Lets make sure the body is activated
$('body').addClass('rsSlider-active');
$('.loader').show().transition({
opacity: 1
}, 100, 'easeInOutQuart');
// $('.socialbar-vertical-static').removeClass('activestate');
$('.body').transition({
opacity: 0
}, 100, 'easeInOutQuart');
// After slider loads
setTimeout(function () {
$('.body').transition({
opacity: 1
}, 500, function() {
$('.loader').transition({
opacity: 0
}, 500).hide();
});
theSliderActivated();
theSocialActivated();
sliderObject.updateSliderSize(true);
$('div#container').css('margin',0);
}, 1000);
});
//});
}
The script is also loaded in at the top like so:
init: function() {
var app = this;
this.fakingIt();
this.loadSlide();
this.unloadSlide();
this.mobileNav();
this.loadThumbs();
this.royalSlider();
this.thumbsSwitch();
this.functionResize();
this.theSocialActivated();
this.slideEventChange();
console.log('======> new.global.js');
}
For some reason it will not register the event at all and even with a console log after the click nothing registers at all.
Am I doing something really wrong here?
Make sure you are definitely calling init() from within a document ready event handler. This will ensure the rsThumb div is available when binding to its click event.
$(function(){
init();
});

some issues with mouseenter and mouseleave functions

I have this function:
$(".insidediv").hide();
$(".floater").mouseenter(function(){
$(".hideimg").fadeOut(function(){
$(".insidediv").fadeIn();
});
});
$(".floater").mouseleave(function(){
$(".insidediv").fadeOut(function(){
$(".hideimg").fadeIn();
});
});
the function built to make a little animation, when you 'mouseenter' the div the picture I have there is hidden and than a few text show up.
it works fine if i move the mouse slowly. but if i move my mouse fast over the div the function getting confused or something and it shows me both '.insidediv and .hideimg,
how can i fixed that little problem so it wont show me both? thanks!
You need to reset the opacity, because fadeIn and fadeOut uses this css property for animation. Just stopping the animation is not enough.
This should work:
var inside = $(".insidediv"),
img = $(".hideimg");
duration = 500;
inside.hide();
$(".floater").mouseenter(function () {
if (inside.is(":visible"))
inside.stop().animate({ opacity: 1 }, duration);
img.stop().fadeOut(duration, function () {
inside.fadeIn(duration);
});
});
$(".floater").mouseleave(function () {
if (img.is(":visible"))
img.stop().animate({ opacity: 1 }, duration);
inside.stop().fadeOut(duration, function () {
img.fadeIn(duration);
});
});
I just introduced the duration variable to get animations of equal length.
Here is a working fiddle: http://jsfiddle.net/eau7M/1/ (modification from previous comment on other post)
try this:
var $insideDiv = $(".insidediv");
var $hideImg = $(".hideimg");
$insideDiv.hide();
$(".floater").mouseenter(function(){
$hideImg.finish().fadeOut(function(){
$insideDiv.fadeIn();
});
}).mouseleave(function(){
$insideDiv.finish().fadeOut(function(){
$hideImg.fadeIn();
});
});
This will solve your issue:
var inside = $(".insidediv"),
img = $(".hideimg");
inside.hide();
$(".floater").hover(function () {
img.stop(true).fadeOut('fast',function () {
inside.stop(true).fadeIn('fast');
});
},function () {
inside.stop(true).fadeOut('fast',function () {
img.stop(true).fadeIn('fast');
});
});
Updated Fiddle
You need to set the 'mouseleave' function when the mouse is still inside the
'floater' div.
Try this (i have tried it on the jsfiddle you setup and it works):
.....
<div class="floater">Float</div>
<div class="insidediv">inside</div>
<div class="hideimg">img</div>
var inside = $('.insidediv'),
img = $('.hideimg');
inside.hide();
$('.floater').mouseenter( function() {
img.stop().hide();
inside.show( function() {
$('.floater').mouseleave( function() {
inside.hide();
img.fadeIn();
inside.stop(); // inside doesn't show when you hover the div many times fast
});
});
});
.....

How do I change images every 6 seconds? [duplicate]

This question already has an answer here:
How can I execute javascript code every a specific time interval?
(1 answer)
Closed 9 years ago.
How do I add an interval to the below code so it does it change images automatically every 6 seconds?
I use this code from fearlessflyer.com
$(window).load(function () {
var theImage = $('ul li img');
var theWidth = theImage.width();
//wrap into mother div
$('ul').wrap('<div id="mother" />');
//assign height width and overflow hidden to mother
$('#mother').css({
width: function () {
return theWidth;
},
height: function () {
return theImage.height();
},
position: 'relative',
overflow: 'hidden'
});
//get total of image sizes and set as width for ul
var totalWidth = theImage.length * theWidth;
$('ul').css({
width: function () {
return totalWidth;
}
});
$(theImage).each(function (intIndex) {
$(this).nextAll('a')
.bind("click", function () {
if ($(this).is(".next")) {
$(this).parent('li').parent('ul').animate({
"margin-left": (-(intIndex + 1) * theWidth)
}, 1000)
} else if ($(this).is(".previous")) {
$(this).parent('li').parent('ul').animate({
"margin-left": (-(intIndex - 1) * theWidth)
}, 1000)
} else if ($(this).is(".startover")) {
$(this).parent('li').parent('ul').animate({
"margin-left": (0)
}, 1000)
}
}); //close .bind()
}); //close .each()
}); //doc ready
Here is an extended answer
var intNum = 6000; //repeat every 6 seconds
function startInterval(){
window.int = setInterval(function(){
//code to move to next image
},intNum);
}
That will set the interval for the image, going to the next automatically, small adjustments might be needed when comparing to your click event for the switch, so I left the inside blank.
the function startInterval() should be called when you know that the rest of the code is loaded and ready (click events are set, ect).
When you do a click event to manually switch back and forth you want to use the following
clearInterval(int);
//code to switch image from click
startInterval();
You need to use the setInterval() function.
Basically, it would look something like:
var currentImg=0;//Current image tracker
var imgList["img1.jpg","img2.jpg","img3.jpg"];//Image names
var changeImage = function(){
//Change src attribute on img element
$('ul li img').attr('src','/imgdir/'+imgList[currentImg]);
if(currentImg>=imgList.length-1)//Check if current image is the last in the list
currentImg=0;//Sets to first images if true
else
currentImg++;//Sets to next image if false
}
//Sets an interval of 6000ms on the window object that calls the function changeImage()
//on every trigger
window.setInterval(changeImage(),6000);
MDN Reference
Hope this helps, I'd suggest checking out the jQuery Documentation aswell...
Use the setInterval() javascript function, as explained here.

Implementing Hover Intent

I just finished developing this Wordpress theme:
http://www.minnesdiner.com/
Everything is working well, but I'm not 100% happy with the navigation.
The sliding position indicator works smoothly, but I'd like to integrate the hover intent jQuery plugin to prevent the sliding indicator from sliding when the user unintentionally passes over the nav.
Any ideas as to how I could integrate this plugin? I'm currently firing a separate jQuery function for each nav item and passing coordinates to the sliding indicator based on which item is being hovered upon.
Here's my current jQuery code:
$(document).ready(function() {
var $currentpos = $("#menu-indicator").css("left");
$("#menu-indicator").data('storedpos', $currentpos);
$(".current-menu-item").mouseenter(function () {
$("#menu-indicator").stop().animate({left: $currentpos}, 150);
});
$(".menu-item-26").delay(500).mouseenter(function () {
$("#menu-indicator").stop().animate({left: "52px"}, 150);
});
$(".menu-item-121").mouseenter(function () {
$("#menu-indicator").stop().animate({left: "180px"}, 150);
});
$(".menu-item-29").mouseenter(function () {
$("#menu-indicator").stop().animate({left: "310px"}, 150);
});
$(".menu-item-55").mouseenter(function () {
$("#menu-indicator").stop().animate({left: "440px"}, 150);
});
$(".menu-item-27").mouseenter(function () {
$("#menu-indicator").stop().animate({left: "570px"}, 150);
});
$(".menu-item-164").mouseenter(function () {
$("#menu-indicator").stop().animate({left: "760px"}, 150);
});
$delayamt = 400;
$("#header-row2").click(function () {
$delayamt = 5000;
});
$("#header-row2").mouseleave(function () {
$("#menu-indicator").stop().delay($delayamt).animate({left: $currentpos}, 600);
});
});
As you can see, I need to bind mousover and mouseout to separate elements (list-item and containing div).
Thanks!
If all you want to do is avoid the user triggering the slide by mousing over the nav, I would just setTimeout in your hover function to call your sliding code after a certain amount of time has passed, and clear the timeout on the mouseout event. No extra plugin needed.
For example:
var hover_timer;
$('.menu-item').hover(
function() {
hover_timer = setTimeout(function() {
...
}, 500);
},
function() { clearTimeout(hover_timer); }
);
EDIT: by the by, you should be combining all those hover functions into one. You can do something like:
$('.menu-item-26').data('slider-pos', '52px');
$('.menu-item-121').data('slider-pos', '180px');
...
And then in the code to slide, call it back:
$this = $(this);
$('#menu-indicator').stop().animate({left: $this.data('slider-pos')}, 150);
And that's just a start - you can generalize it even more, I bet.

jquery small error

i am very new at jquery and code, here i am trying to get the setTimeout event to be inside the .mouseout event but i'm not sure how to do that as i keep getting syntax error in my editor. Here's what i have:
jQuery(document).ready(function() {
$('.slidedown').hide();
$('.trigger').hover( function(){ // enter animation
$('.slidedown').stop(true,true).animate({
height: ['toggle', 'swing'],
}, 600, function() { /* animation done */ });
}, function(){ // leave animation
$('.slidedown').mouseout()
setTimeout( function(){
$('.slidedown').stop(true,true).animate({
height: '0px',
}, 600, function() { /* animation done */ });
}, 1000 );
});
});
A small nuance, in this code the user mouses over a div, then another div bellow it slides down. Moving the mouse to the .slidedown div should keep it open until the mouse is removed. But will this code collapse the .slidedown div if the user doesn't mouse over .slidedown after .trigger but instead moves the mouse directly from .trigger to another area of page? I.e i need some kind of 'setTimeout' that is trigged only if the user doesn't move mouse over .slidedown after hovering over .trigger. Hope i make sense. Thanks for your help!
This line is the problem
$('.slidedown').mouseout()
It shoule be
$('.slidedown').mouseout( YOUR_CALLBACK_FUNCTION )
You should pass a callback function which will act as an event handler and inside that event handler you can call setTimeout() the way you have done it.
So the correct code would look like this
$('.slidedown').mouseout( function() {
setTimeout( function(){
$('.slidedown').stop(true,true).animate( {
height: '0px',
},
600,
function() { /* animation done */ }
); // animate ends here
}, 1000 ); // setTimeout ends here
}); // mouseout ends here
Thanks T.J and Arnab, this works:
$(document).ready(function() {
$('.slidedown').hide();
$('.trigger').hover( function(){ // enter animation
$('.slidedown').stop(true,true).animate({
height: ['toggle', 'swing'],
}, 600, function() { /* animation done */ });
}, function(){ // leave animation
$('.slidedown').mouseout( function() {
setTimeout( function(){
$('.slidedown').stop(true,true).animate( {
height: '0px',
},
600,
function() { /* animation done */ }
); // animate ends here
}, 1000 ); // setTimeout ends here
}); // mouseout ends here
});
});
But the other thing i mentioned about moving the mouse over .trigger but then away (but not into .slidedown) doesn't work. The .slidedown just remains open. :) :( I think it will be very complex to get a .mouseout event that has a kind of 'allow' rule for one destination of the mouse.

Categories

Resources