Funky jQuery mouseleave behavior
Asked Answered
S

5

6

I have a menu-like drop down container that hides via binding the "mouseleave" event.

<div id="container">
<select>
    <option>1</option>
    <option>2</option>
    <option>3</option>
    <option>4</option>
    <option>5</option>
</select>
</div>

The problem I am having is when my container's child elements contain a SELECT object where the OPTIONS of the SELECT physically extend outside the bounds of the container. Consequently, hovering over the OPTIONS outside of the bounds trigger the "mouseleave" event to fire and close my drop down. The SELECT is a child of the container, so in this case I would expect the mouseleave event to recognize this.

Shaker answered 19/1, 2010 at 20:32 Comment(2)
Why not make the container always large enough to contain its children?Touchback
The number of options are much larger than the containing element. I want to keep the UI as simple as possible.Shaker
B
4

An update on Blocka's solution as it doesn't work with Firefox correctly:

if ((typeof e.fromElement != 'undefined' && !e.fromElement.length) ||
    (typeof e.fromElement == 'undefined' && e.target.tagName != 'SELECT')) {
    // perform your mouseleave logic
}
Benighted answered 16/8, 2011 at 13:29 Comment(0)
C
4

A very simple and effective solution to this is to control the mouse pointer coordinates before performing the action. If the container out of focus to focus on the element "select", it checks the pointer. If the pointer is inside the container, it does not perform any action, however if this is the container element action is performed

 $('#div_solapa_lateral').bind("mouseenter",function(){
            $(this).animate({left:'0'},500);
        });

    $('#div_solapa_lateral').bind("mouseleave",function(e){
            if ( e.clientX>360 || e.clientY<60 || e.pageY>625 )
            $(this).animate({left:'-320'},500);
        });

clientX and clientY to "position:relative;" pageX and pageY to "position:absolute;"

Capapie answered 31/10, 2012 at 23:1 Comment(0)
S
2

Thanks eyelidlessness! I actually found another answer to this problem last night that is very similar to what you posted.

.bind("mouseleave", function(e) { // ANSWER HERE!!!
    if (!e.fromElement.length) {
        _state.filterTrigger.data("open", false);
        setTimeout(function() { _toggleFilter(_state.filterTrigger); }, 2000);
    }
});

The e.fromElement object gives the count of OPTION objects in the SELECT. This object is undefined for other HTML tags. I haven't tried your solution but this works for me as well.

Shaker answered 20/1, 2010 at 16:37 Comment(0)
U
1

Perhaps when the dropdown is expanded you could set a flag. Clear the flag when an item is selected. When a mouseleave occurs, don't hide the menu unless the flag is clear.

I always get nervous about hacking UI events to this degree though, since it's likely you'll end up leaving some browser somewhere in a totally unusable state.

Upanchor answered 19/1, 2010 at 20:39 Comment(1)
Thank you for you response. Ideally I would like the mouseleave event to fire when I leave the OPTION tags without going back to the SELECT or the containing DIV. The trick is to avoid binding events to the OPTION tags as well. There are a number of small hacks I could try but I was looking for a more core structured solution.Shaker
J
1

Most renderers (all except Gecko, I think) implement opened <select> menus and their options in a separate "window", not as elements on the page. The page is, then, not necessarily aware of the user's interaction with an open <select> menu. It's very unlikely that you'll be able to achieve the desired effect across all the major browsers...

Edit: ... but maybe so. This works for me in Safari and Firefox. I can't test in IE right now, but give it a shot:

var timer;
$('#container').mouseleave(function(e) {
    if($(e.target).parents('#container').length) {
        return;
    }
    timer = setTimeout(function() {
        $('#container select').blur();
    }, 50);
}).mouseenter(function(e) {
    if(timer) {
        clearTimeout(timer);
    }
});

Edit 2: actually, Safari doesn't fire mouseleave (or mouseout) at all when the <select> "window" is open.

Janeejaneen answered 19/1, 2010 at 20:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.