How to disable mouseout events triggered by child elements?
Asked Answered
J

9

112

Let me describe the problem in details:

I want to show an absolute positioned div when hovering over an element. That's really simple with jQuery and works just fine. But when the mouse goes over one of the child elements, it triggers the mouseout event of the containing div. How do I keep javascript from triggering the mouseout event of the containing element when hovering a child element.

What's the best and shortest way to do that with jQuery?

Here is a simplified example to illustrate what I mean:

Html:

<a>Hover Me</a>
<div>
  <input>Test</input>
  <select>
    <option>Option 1</option>
    <option>Option 2</option>
  </select>
</div>

Javascript/jQuery:

$('a').hover( function() { $(this).next().show() }
              function() { $(this).next().hide() } );
Jigaboo answered 8/12, 2008 at 19:48 Comment(1)
Without jQuery version of this questionToussaint
N
221

The question is a bit old, but I ran into this the other day.

The simplest way to do this with recent versions of jQuery is to use the mouseenter and mouseleave events rather than mouseover and mouseout.

You can test the behavior quickly with:

$(".myClass").on( {
   'mouseenter':function() { console.log("enter"); },
   'mouseleave':function() { console.log("leave"); }
});
Nagpur answered 24/7, 2009 at 17:4 Comment(3)
Helped my non-jquery javascript related problem. I was using mouseenter/mouseout instead of mouseleave with my event listeners!Crotchety
For search sake, these mouse event behaviors are equivalent to ROLL_OVER and ROLL_OUT in AS3.Vas
Saved me some headaches. Its odd how hovering on child elements triggers the parent's mouseout event, when in fact its is still inside the parent element.Antitoxic
S
18

For simplicity sake, I would just reorganize the html a bit to put the newly displayed content inside the element that the mouseover event is bound to:

<div id="hoverable">
  <a>Hover Me</a>
  <div style="display:none;">
    <input>Test</input>
    <select>
      <option>Option 1</option>
      <option>Option 2</option>
    </select>
  </div>
</div>

Then, you could do something like this:

$('#hoverable').hover( function() { $(this).find("div").show(); },
                       function() { $(this).find("div").hide(); } );

Note: I don't recommend inline css, but it was done to make the example easier to digest.

Segarra answered 8/12, 2008 at 20:16 Comment(2)
This is indeed a very simple and clean solution. Thanks for reminding me. But in my specific situation, which is not exactly as in the question, this is nog an option. Thanks though!Jigaboo
After trying different methods as described by others here at SO, i came back to your method and made it work in my case. Yay! :-)Jigaboo
P
11

Yeap, guys, use .mouseleave instead of .mouseout:

$('div.sort-selector').mouseleave(function() {
    $(this).hide();
});

Or even use it in combination with live:

$('div.sort-selector').live('mouseleave', function() {
    $(this).hide();
});
Pankhurst answered 18/9, 2015 at 10:21 Comment(0)
K
9

You are looking for the jQuery equivalent of javascript's prevent event bubbling.

Check this out:

http://docs.jquery.com/Events/jQuery.Event#event.stopPropagation.28.29

Basically you need to catch the event in the children DOM nodes, and there stop their propagation up the DOM tree. Another way, although really not suggested (as it can severely mess with existing events on your page), is to set event capture to a specific element on the page, and it will receive all the events. This is useful for DnD behavior and such, but definitely not for your case.

Krystlekrystyna answered 8/12, 2008 at 20:30 Comment(1)
this works as it should, don't know why you couldn't get it working.. just an info, a link to docs has changed, new link is docs.jquery.com/Events/jQuery.Event#event.stopPropagation.28.29Dissolvent
W
3

I'm simply checking if the mouse-coordinates is outside the element in the mouseout-event.

It works but it's alot of code for such a simple thing :(

function mouseOut(e)
{
    var pos = GetMousePositionInElement(e, element);
    if (pos.x < 0 || pos.x >= element.size.X || pos.y < 0 || pos.y >= element.size.Y)
    {
        RealMouseOut();
    }
    else
    {
         //Hit a child-element
    }
}

Code cut down for readability, won't work out of the box.

Without answered 8/12, 2008 at 20:28 Comment(0)
R
2

I resolved this problem by adding pointer-events: none; on my child elements css

Ralston answered 15/11, 2017 at 16:46 Comment(3)
This really helped a lot when fixing some legacy code building its own popovers with mouseover and mouseleave eventsGrin
Yes, that's the most elegant solution.Fissionable
However, it disables the click events too, which is not necessarily desired, but it's still okay.Fissionable
H
1

I agree with Ryan.

Your problem is that the "next" div is not a "child" of A. There's no way for HTML or jQuery to know that your "a" element is related to the child div in the DOM. Wrapping them and putting a hover on the wrapper means that they are associated.

Please note that his code isn't in line with best practices, though. Don't set the hidden style inline on the elements; if the user has CSS but not javascript, the element will hide and will not be able to be shown. Better practice is to put that declaration in the document.ready event.

Handrail answered 8/12, 2008 at 21:8 Comment(1)
I totally agree with putting the hide in the document.ready event. The inline css was just to convey a full working example in the simplest way possible. I'll edit my response to make that clear.Segarra
L
0

The way I've usually seen this handled is to have a delay of about 1/2 second between moving the mouse from the HoverMe element. When moving the mouse into the hovered element, you would want to set some variable which signals that you are hovering over element, and then basically stop the hovered part from hiding if this variable is set. You then have to add a similar hide function OnMouseOut from the hovered element to make it disappear when you remove the mouse. Sorry I can't give you any code, or something more concrete, but I hope this points you in the right direction.

Lallage answered 8/12, 2008 at 20:25 Comment(1)
Yes idd I've just implemented a solution like that. It's a really common problem. I'm really curious what other solution there are... Thanks for answer!Jigaboo
P
0

It's an old question, but it never gets obsolete. The correct answer should be the one given by bytebrite.

I would only like to point out the difference between mouseover/mouseout and mouseenter/mouseleave. You can read a great and helpful explanation here (go to the very bottom of the page for a working demo). When you use mouseout, the event stops when the mouse enters another element, even if it's a child element. On the other side, when you use mouseleave, the event is not triggered when the mouse overs a child element, and this is the behaviour the OP would like to achieve.

Patricio answered 2/4, 2013 at 13:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.