Prevent function running for lots of clicks - javascript

Sorry for the misleading title its hard to explain!
Basically I have a function that when you click left/right a div moves X pixels either way.
// Upcoming events slide
$('.nextEvent').click(function(e){
e.preventDefault();
if($('.newsColWrap').offset().left == '597.5'){
} else {
$('.newsColWrap').stop(true,true).animate({'left' : "-=435px"},500)
}
});
$('.prevEvent').click(function(e){
e.preventDefault();
if($('.newsColWrap').offset().left == '1032.5'){
} else {
$('.newsColWrap').stop(true,true).animate({'left' : "+=435px"},500);
}
});
The function works fine, but if the animations is happening and you click again, because the if statement doesn't return my div moves too far, does this make sense?

You can check if the element is being animated using :animated before animating it again.
$('.nextEvent').click(function(e){
e.preventDefault();
if($(this).is(':animated')) return; // check if currently being animated
// ... animate
});
$('.prevEvent').click(function(e){
e.preventDefault();
if($(this).is(':animated')) return; // check if currently being animated
// ... animate
});

The problem could be that you are reading the offset before the previous animation is completed so try
$('.nextEvent').click(function (e) {
e.preventDefault();
var $newsColWrap = $('.newsColWrap').stop(true, true);
if ($newsColWrap.offset().left == '597.5') {
} else {
$newsColWrap.animate({
'left': "-=435px"
}, 500)
}
});
$('.prevEvent').click(function (e) {
e.preventDefault();
var $newsColWrap = $('.newsColWrap').stop(true, true);
if ($newsColWrap.offset().left == '1032.5') {
} else {
$newsColWrap.stop(true, true).animate({
'left': "+=435px"
}, 500);
}
});

You could use a simple setTimeout function running for 500.

Related

mouseenter bubbling when mousehover multiple times

how to prevent bubbling or "out of control" when user hover(mouseenter) multiple times . When user hover i'm using slideDown and slideUp for mouseleave and delay i set 250. I can only fix this if delay i set to 1 ms. Below is my script :
$("#nav li").mouseenter(function (e) {
e.stopPropagation();
if (!is_opened) {
var left = $(this).position().left;
$(this).children('div').css('left', '-' + left + 'px');
$(this).children('div').slideDown(delay, function () {
// Animation complete.
is_opened = true;
});
}
return false;
});
$("#nav li").mouseleave(function () {
if (is_opened) {
$(this).children('div').slideUp(delay, function () {
// Animation complete.
is_opened = false;
});
} else {
setTimeout(function () {
if (is_opened) {
$('#nav li:first-child').children('div').slideUp(delay, function () {
// Animation complete.
is_opened = false;
});
}
}, 1000);
}
return false;
});
You can check my JsFiddle here
Reproduce a Problem
Hover Catalogue multiple times and stop hover(but point your cursor at Catalogue), you will see the dropdown will hide but actually it should slide down.
I think your issue is caused by the is_opened flag and then the animation being run along side changing the left css property
If you change your mouse enter and leave js to the following
$("#nav li").each(function() {
//cache vars for better performance
var li = $(this);
var left = $(this).position().left;
var divs = li.children('div');
//change div left first so it only changes once
divs.css('left', '-' + left + 'px');
//do mouse enter and leave stuff
li.mouseenter(function (e) {
e.stopPropagation();
divs.stop(true, true).slideDown(delay);
});
li.mouseleave(function () {
divs.stop().slideUp(delay);
return false;
});
});
it should work: Example

Div doesn't Animate after stop()

What I'm trying to do is, whenever we leave the button and then move back to the grey content box, the slideUp will stop and the content will be slideDown again.
It works just fine using jQuery 1.x (edge), but when I use jQuery 1.10 the slideUp just stop, and not continue to slideDown again.
Do you guys have any idea which part should I change to make it work on jQuery 1.10?
$(function () {
var show_content = '';
$('.nav-content > div').hide();
$('.btn1,.btn2').mouseenter(function (e) {
var target = $(e.currentTarget).attr('class');
console.log('Mouse Enter : ' + target);
if (target == 'btn1') {
show_content = $('.con1');
} else if (target == 'btn2') {
show_content = $('.con2');
}
show_content.stop().slideDown(300);
});
$('.btn1,.btn2').mouseleave(function (e) {
var target = $(e.currentTarget).attr('class');
show_content.stop().slideUp(2000);
});
$('.nav-content').mouseenter(function (e) {
show_content.stop().slideDown(300);
});
$('.nav-content').mouseleave(function (e) {
show_content.stop().slideUp(2000, 'swing', function (e) {
console.log('Hide done');
});
});
});
Here's my Fiddle
http://jsfiddle.net/PmJt2/2/
I can't figure out why not continue to slideDown again, but slideToggle works.
Use .slideToggle() instead of slideDown and slideUp

jQuery - when clicking on elements too fast animations get buggy

I've been working on this jQuery effect heres the fiddle:
http://jsfiddle.net/abtPH/26/
Everything's pretty good so far, however when I click on the elements too fast it seems to get buggy and get weird behavior. If you take your time and click on the elements it works fine.
I've tried using :animate
stuff to make sure the animation ends before the user can click on the next one. I do not like this approach though because from a end user it seems like the effects are laggy. I want the user to be able to click on the elements fast and have the desired effect.
Here's my jQuery so far:
$('li').on('click', function (e) {
e.preventDefault();
var active = $(this).siblings('.active');
var posTop = ($(this).position()).top;
if (active.length > 0) {
var activeTop = (active.position()).top;
if (activeTop == posTop) {
$(this).find('.outer').fadeIn('medium', function () {
active.toggleClass('active', 400).find('.outer').fadeOut('medium');
});
} else {
$(this).siblings('.active').toggleClass('active', 400).find('.outer').slideToggle();
$(this).find('.outer').slideToggle();
}
} else {
$(this).find('.outer').slideToggle();
}
$(this).toggleClass('active', 400);
});
$('.outer').on('click', function (e) {
return false;
});
Use .finish() complete all the queued animation before beginning a new one
$('li').on('click', function(e){
e.preventDefault();
var active = $(this).siblings('.active');
var posTop = ($(this).position()).top;
if (active.length > 0) {
var activeTop = (active.position()).top;
if (activeTop == posTop) {
$(this).find('.outer').finish().fadeIn('medium', function(){
active.finish().toggleClass('active', 400).find('.outer').finish().fadeOut('medium');
});
} else {
$(this).siblings('.active').finish().toggleClass('active', 400).find('.outer').finish().slideToggle();
$(this).find('.outer').finish().slideToggle();
}
} else {
$(this).find('.outer').finish().slideToggle();
}
$(this).finish().toggleClass('active', 400);
});
$('.outer').on('click', function(e){
return false;
});
Demo: Fiddle

jQuery mousemove fade in/out element cancel fade on element mouseover

I have written this code which fades out the navigation menu to 50% opacity when the mouse is dormant:
var hidden, fadenav, dimNav = function () {
hidden = true;
$('#main-nav').animate({'opacity': 0.5}, 200);
};
$('document').ready(function () {
dimNav();
$('body').on('mousemove', function (e) {
if (hidden) {
$('#main-nav').animate({'opacity': 1}, 200);
hidden = false;
}
if (fadenav !== null) {
clearTimeout(fadenav);
}
fadenav = setTimeout(dimNav, 500);
});
});
What I want to do is make it so that it doesn't fade when the user has their mouse over the #main-nav element.
I have tried this to no avail:
$('#main-nav').on('mouseover mouseout', function (e) {
if (e.type === 'mouseover') {
clearTimeout(fadenav);
} else {
fadenav = setTimeout(dimNav, 500);
}
});
does anyone have any idea how to do this?
Well this certainly is not less code but it may be a bit more straight forward:
​$('#main-nav').on('mousemove',function(e){
if(hidden){
$('#main-nav').animate({'opacity': 1}, 200);
hidden = false;
}
clearTimeout(fadenav);
e.stopPropagation();
});
add that instead of:
$('#main-nav').on('mouseover mouseout', function (e) {
if (e.type === 'mouseover') {
clearTimeout(fadenav);
} else {
fadenav = setTimeout(dimNav, 500);
}
});
you don't have to play with classes at all.
Here is my working sample: http://jsfiddle.net/TbwSA/1
EDIT: I realized that you don't even need the mouseout event.
I discovered the solution myself and thought it might be worth other people knowing:
first, you need to do something similar to this:
$('#main-nav').on('mouseover', function (e) {
if (!$('#main-nav').hasClass('hovered')) {
$('#main-nav').addClass('hovered');
}
}).on('mouseout', function () {
if ($('#main-nav').hasClass('hovered')) {
$('#main-nav').removeClass('hovered');
}
});
and then change the dimNav() function to this:
dimNav = function() {
if (!$('#main-nav').hasClass('hovered')) {
hidden = true;
$('#main-nav').css('opacity', '0.5');
}
};
If anyone can think of a better method than this, please contribute!

Catch scrolling event on overflow:hidden element

Any insights on how to catch a scrolling event on a element that has overflow:hidden? I would like to scroll in a column without showing a scrollbar to the user.
This is actually a somewhat indepth process. What I do is set global flags when users mouse enters and leaves the element that you want to scroll. Then, on the mousewheel event for the body I check to see if the MOUSE_OVER flag is true, then stop propagation of the event. This is so the main body doesnt scroll in case your entire page has overflow.
Note that with overflow hidden, the default scrolling ability is lost so you must create it yourself. To do this you can set a mousewheel listener on your div in question and use the event.wheelDelta property to check whether the user is scrolling up or down. This value is different according to browser, but it is generally negative if scrolling down and positive if scrolling up. You can then change position of your div accordingly.
This code is hacked up quickly but it would essentially look like this...
var MOUSE_OVER = false;
$('body').bind('mousewheel', function(e){
if(MOUSE_OVER){
if(e.preventDefault) { e.preventDefault(); }
e.returnValue = false;
return false;
}
});
$('#myDiv').mouseenter(function(){ MOUSE_OVER=true; });
$('#myDiv').mouseleave(function(){ MOUSE_OVER=false; });
$('#myDiv').bind('mousewheel', function(e){
var delta = e.wheelDelta;
if(delta > 0){
//go up
}
else{
//go down
}
});
I use overflow:scroll, but also Absolutely position a div over the scroll bar in order to hide it.
$("body").css("overflow", "hidden")
$(document).bind('mousewheel', function(evt) {
var delta = evt.originalEvent.wheelDelta
console.log(delta)
})
works for me. adapted from How do I get the wheelDelta property?
I edited #anson s answer to Vanilla Javascript since it may be useful for others. Also note that "mousewheel" event is deprecated. So my code uses "wheel" instead. Next to that I added arrow functions for practical access the to "this".
fixScrollBehavior(elem) {
elem.addEventListener('scroll', (e) => {
console.log('scrolling');
});
let MOUSE_OVER = false;
elem.addEventListener('wheel', (e) => {
if (MOUSE_OVER) {
if (e.preventDefault) {
e.preventDefault();
}
e.returnValue = false;
return false;
}
});
elem.addEventListener('mouseenter', () => {
MOUSE_OVER = true;
});
elem.addEventListener('mouseleave', () => {
MOUSE_OVER = false;
});
elem.addEventListener('wheel', (e) => {
let delta = e.wheelDelta;
if (delta > 0) {
//go up
} else {
//go down
}
});
}
Note that this does not fix the mobile touch-"scroll"s.
$("div").on('wheel', function (e) {
if (e.originalEvent.deltaY < 0) {
console.log("Scroll up");
} else {
console.log("Scroll down");
}
});
This did the trick for me.
JSFiddle
StackFiddle:
$("div").on('wheel', function(e) {
if (e.originalEvent.deltaY < 0) {
console.log("Scroll up");
} else {
console.log("Scroll down");
}
});
div {
height: 50px;
width: 300px;
background-color: black;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>
I am late, but I think I have a better answer.
Style your container as overflow: overlay, this will free up space of scrollbar, then style scrollbar or hide it or make its handle height/width 0,
Then you should get scroll events also.
Note : styling the scrollbar is not supported in all web browsers.

Categories