Hover state sticks when leaving the page- ignores mouseleave - javascript

I'm using some pretty standard JavaScript/jQuery to handle hovering elements, image swaps, sliding divs, animations, etc., it does not matter. If/when clicking an "hoverable" linked element takes you to a new page, the mouseenter hover state always sticks.
For example, if you hover over something and click it (links to another page), then use the back button to return to the page, the mouseenter state on the element you clicked, is stuck even though your mouse is no longer over the element.
You have to either reload the page or re-hover the element to reset everything.
$(document).ready(function() {
$('.mySelector').each(function () {
$(this).hover(enter, leave);
});
function enter(event) {
// mouseenter stuff
};
function leave(event) {
// mouseleave stuff
};
});
I seem to remember reading about this several weeks ago and there was a very simple fix but I can no longer find that.
Is anyone familiar with a proper solution?
Thank-you!

You don't need to use .each for this. Also, the functions should be outside .ready.
$(document).ready(function() {
$('.mySelector').hover(enter, leave);
});
function enter(event) {
// mouseenter stuff
}
function leave(event) {
// mouseleave stuff
}
Edit:
If your variables are local, you could do it like this:
$(document).ready(function() {
$('.mySelector').hover(function(){
// mouseenter stuff
},
function(){
// mouseleave stuff
});
});

I ended up simply "re-setting" the hover effects by calling the mouse leave function with the window "unload"...
$(window).unload(function() {
leave();
});
Whenever you leave the page by clicking the hovered element, the mouseleave function is called even though your mouse is still hovering over the element. Hitting the browser's back button no longer takes you back to the page with a "stuck" hover effect.
Problem solved.

Related

jQuery Mouseover AND Mouseout With on AND off not working

I have a few functions in jQuery that control the display of a div when the parent div is moused over. The first two functions are :
$(".parentDiv").mouseover(function () {
$(this).find(".childDiv").css('visibility','visible');
});
$(".parentDiv").mouseout(function () {
$(this).find(".childDiv").css('visibility','hidden');
});
These work fine. Later, I have a click function bound to the 'childDiv':
$(".childDiv").click(function (e) {
});
I have a bunch of functionality within this function that work perfectly. However, at one point I need to disable the mouseover and mouseout functions on the parent div. I do this by:
$("#" + this.id).closest(".parentDiv").off("mouseover mouseout");
This works perfectly. But, when I try to turn it on based on other functionality in the function using:
$("#" + this.id).closest(".parentDiv").on("mouseover mouseout");
It does not turn back on. I know the selector is working, first because it works when I turn it off, but also because I added the following code and it works:
$("#" + this.id).closest(".parentDiv").css("border","1px solid #000");
Does anyone know why this is not working? I find it strange that turning the mouseover and mouseout off works, and that changing the border also works, but that turning mouseover and mouseout on does not work. What am I missing?
That is because .off doesn't 'turn off' the events, it removes event handlers.
https://api.jquery.com/off/
If you want the events back, you will have to attach them again.

Is it possible to detect a mouse click on a page on every element?

I want to trigger a function if a user clicks anywhere on the page, even clicking on no element or link. Is it possible?
The extension runs only on youtube.com so I can't add every element on the page to the trigger and I assume that every page has different element's ids.
Emmanouil Chountasis is correct, you can use the code at "Detect left mouse button press" to detect a left mouse click crossbrowser.
To the heart of your question, I think what you're looking for is Event Delegation. In jQuery,
// Select a wrapper for the events
$('body')
// Whenever any element in the <body> is clicked
.on('click', '*', function (evt) {
// Emmanouil Chountasis's suggestion would be called right here
if (isLeftClick(evt)) {
// ... do stuff
}
});
See http://learn.jquery.com/events/event-delegation/
Reed's answer works fine, but it triggers the action multiple times. I found this solution that only works on left mouse triggers and executes once per click.
$("body").unbind().click(function() {
//Do Stuff
});

jQuery mobile swipe spamming and animation

I have say 5 list items with images inside placed 200px from eachother.
I am trying to animate these list items to slide horizontally left if one presses a link with the id = #next or if one swipes left. And vice versa for sliding the list items right.
Every click or swipe results in a slide animation of 200px on every list item.
I ran into a problem where spamming the #next or #prev button would cancel the current animation and start a new one. This results in list items not sliding 200px+200px+200... but something like this 200px+140px+120... This because like I said the animation is cut and therefore the sliding distance will be shorter.
Now I solved this for the clicking event by disabling the button before the animation starts and then re'enabling it on the end callbak function. But this problem is remaining for the swipe event.
How can I solve this problem for the swipe event?
If you have the code working for your click event handlers, then just .trigger() a click event on the proper element for each of the swiperight and swipeleft events:
$(document).delegate('#next', 'click.my-namespace', function () {
...
}).delegate('#prev', 'click.my-namespace', function () {
...
}).delegate('#my-page-id', 'swipeleft swiperight', function (event) {
if (event.type == 'swipeleft') {
$('#next').trigger('click.my-namespace');
} else {
$('#prev').trigger('click.my-namespace');
}
});
This way you have a single base of code that does the same thing, that gets called by multiple event handlers. I like to do this when I am adding touch events to a desktop design.
Notice I bound the event handlers with name-spaces so you don't accidentally trigger the wrong event handler.
You can also use .stop(true, true) but it may make your animations jittery when playing many in a row. The best solution when using .stop() is to always animate to an absolute value, never use +=200px, that way when you use .stop() the animation can be stopped and instantly restarted to the new absolute position: http://api.jquery.com/stop
One way you can do it is by setting a boolean variable that is global to the script with the default value of false. Then set the variable to true prior to animating and set it back to false once the animation is complete. Prior to setting off the animation, check the state of the variable, run the animation only if it's false. The code would look something like this:
var isAnimating = false;
function animate()
{
if(!isAnimating) {
//Animation code
isAnimating = false;
}
}
If the animation is asynchronous then you should set isAnimating = false in the completion function of the animation.

How to stop toggle event from being fired multiple times on mouseenter/mouseleave?

I'm using jQuery to toggle the visibility of a <div> using the jQuery toggle method. The toggle is fired on the mouseenter and mouseleave event, thus creating the effect of the div to fold out on mouseenter and fold in on mouseleave. Problem is, if the user drags the mouse over the <div> a few times and then leaves the <div>, the div will toggle in and out several times. This can happen if the user accidentally moves around the mouse pointer in the <div> are. Do anyone have any idea on how I can avoid this behavior?
Thanx!
Two things:
If you're going to use both mouseenter and mouseleave I'd suggest using the hover() function; and
When using triggered animations it's a good habit to get into to use the stop() method.
So:
$("div.someclass").hover(function() {
$("...").stop().fadeIn("slow");
}, function() {
$("...").stop().fadeOut("slow");
});
Note: replace "..." with the appropriate selector for what you're toggling and use the appropriate effect (I'm using fade here). Also, this in an event handler refers to the source of the event.
You can use the more common mouseover/mouseout events to get a hover event that doesn't fire on internal mouse movements.
But don't use toggle on a mouse event, it can easily go wrong if eg. the mouse is over the element at page load time, or the mouse leaves the browser (which can allow the mouse to leave the bounds of the element without firing a mouseout). Have separate function for over which shows the content, and out which hides it.
Better: just use the hover() method which is meant for exactly this purpose.
Aside from the correct answer by Cletus, i'd like to point out that using mouseenter and mouseleave events is not wrong. The trick only resides into the stop() method, in fact we could still do:
$("div.someclass").on("mouseenter", function() {
$("...").stop().fadeIn("slow");
});
$("div.someclass").on("mouseleave", function() {
$("...").stop().fadeOut("slow");
});
Here is a jsFiddle example :)

How do I avoid massive onmouseover onmouseout firing?

I have a table with some columns. In each of them is a picture where I have an onmouseover/onmouseout event on it, which shows a message in a div and hides the message.
My problem is, after a user moves quickly from left to right over a lot of images, all mouseover and mouseout events of the images are executed, which looks stupid...
Is it possible to rearrange the internal event stack to avoid this, such that the user executes only the current event (mostly the first one) and then the last one, if it is not the same type?
For example, if mouseover over first image is executed and the mouse moving position stops over an image three times next to the first one. I can avoid all other events firing, because the mouse stopped over an image and the mouseover is like the one where I stopped with the mouse.
How can I avoid this multiple event firing?
You need to check out the hoverIntent plugin, which addresses this problem.
We've had the exact same problem, What we've done is on the mouseover event is to set a variable _mouseOn to true (set to false on mouseout) then set a oneTime event over that fires in say 500 ms.. The one time event will check if the _mouseOn is true and display the image
function Hover() {
_mouseOn = true;
$(document).oneTime(500, "500ms", functionToCheckTheMouseOnAndDisplayTheImage);
};
//Global timeout handle for mouseover and mouseout
var timeoutHandle;
$(document).ready(function() {
BindMouseHover($(".helptext"));
});//closing ready
//bind mouseover and mouseout actions on all elements
function BindMouseHover(elements) {
$(elements).hover(
function() {
timeoutHandle = setTimeout('HandleMouseHover(true)', 1000);
},
function() {
HandleMouseHover(false);
}
);
}
//Handle Mouseover and mouseout events
function HandleMouseHover(bDelay) {
if (bDelay) {
$(".tooltip").show();
}
else {
$(".tooltip").hide();
clearTimeout(timeoutHandle);
}
}
Explanation:
On every mouseover schedule a call to DelayedTooltip(***true*)** after 1000ms and save the setTimeout handle to timeoutHandle
If mouseout happens within that 1000ms interval then simply call clearTimeout(***timeoutHandle*)** to cancel the setTimeout
This can be easily extended to apply to many heterogeneous elements and wire the customize tooltip text based on the element hovered.
Click here to know more about JavaScript Timing Events.
You can't, and shouldn't try to, avoid the events firing. What you should avoid is your code immediately responding to them by doing something that winds up looking stupid. For example, you can have your mouseovers register, with some controller object, which image the user is currently over, and set a short timeout to the function that triggers the actual behavior (removing a previous timeout if it's already running). The mouseout unregisters the image and removes the timeout. That way, when the behavior runs, you only operate on the image that the user moused over most recently.
I think it's better (from http://bavotasan.com/demos/fadehover/, THANKS)
<script>
$(document).ready(function(){
$(".a").hover(
function() {
$(this).stop().animate({"opacity": "0"}, "slow");
},
function() {
$(this).stop().animate({"opacity": "1"}, "slow");
});
});
</script>

Categories