Friday, May 16, 2008

MooTools mouseenter and mouseleave Events For Dropdowns

posted by Jonah Dempcy

One of the frustrations many coders have encountered when creating JavaScript flyout menus is the fact that onmouseover and onmouseout events fire when entering children elements. This is usually not the desired effect when creating popup, dropdown or flyout menus.

MooTools

MooTools offers its own mouseenter and mouseleave events which alleviate the problem of the events firing when entering child elements, but before diving into that, let's explore why it's such a problem in the first place.

At first thought, it would seem that you want onmouseout to fire when leaving the element, right? Well, generally that's only the case when you're mousing off a flyout menu, for instance. But when you're staying inside the flyout menu and mousing over one of the child elements, you don't want the onmouseout event to fire, since it will have an event handler registered to close the flyout.

Take, for example, this simple flyout menu. Shown here is the barebones HTML for the menu:
  • Level 1
    • Level 2
    • Level 2
    • Level 2
  • Level 1
    • Level 2
  • Level 1
    • Level 2
    • Level 2

This results in a list with 3 top-level headings, each containing 1-3 sub headings. Each sub-heading is represented as a ul element with class flyout-sub, and will be hidden using CSS and only visible when the user mouses over its respective top level heading. Here's the CSS:

ul.flyout-sub {
    display: none;
}
li.active ul.flyout-sub {
    display: block;
}

Pretty simple stuff. We just hide the second level by default and show it if it has a parent li with class active. So, it's up to the JavaScript to toggle the active class.

Here is the JavaScript. Note the use of oldschool JavaScript event registration using the core DOM events onmouseover and onmouseout.

window.addEvent('domready', function() {
    $$('ul.flyout-main > li').each(function(li) {
        li.onmouseover = function() {
            li.addClass('active');
        }
        li.onmouseout = function() {
            li.removeClass('active');
        }
    });
});

If you test this code, you'll see that it doesn't have the desired effect: The onmouseover and onmouseout events fire when entering child elements so you're unable to mouse over the sub menu without closing it. A simple change to MooTools mouseenter and mouseleave events (which only fire when entering/exiting from the parent) solves this problem nicely:

window.addEvent('domready', function() {
    $$('ul.flyout-main > li').each(function(li) {
        li.addEvent('mouseenter', function() {
            li.addClass('active');
        });
        li.addEvent('mouseleave', function() {
            li.removeClass('active');
        });
    });
});

Before I knew about MooTools' mouseenter and mouseleave events, I devised a few workarounds to this using onmouseover and onmouseout. One such solution was to have the event handler function check to see if the targetElement of the event object was a child of the flyout menu. But, whichever solution I devised, it was sub-optimal and involved additional logic for something that should be free in a programming language. Now, thanks to MooTools, it is-- providing you include the MooTools library, of course.

Armed with this knowledge of how mouseenter and mouseleave differ from the conventional onmouseout and onmouseover events, you now have another powerful time-saving tool for making dynamic web interfaces. Instead of mitigating annoying issues with the limited set of core JavaScript events, you can focus on what you want the code to do, not how you want to do it.

For more information, visit the MooTools 1.2 beta docs for Element.Event.

Labels: ,

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home