0

I have some dynamically created menus on a page that need to hide whenever the user clicks anywhere on the page. This needs to work if the user clicks the menu, or tries to open another menu.

I also want the event handler to unbind itself when done hiding. I've found a solution using document.on() one one() but would really like to restrict the document handler to something further down the DOM. Problem is that it breaks my code.

Any help with an elegant solution appreciated.

The main reason I want to do this is to be able to prevent event propagation such as in:

Failing propagation DEMO

Succeeding propagation, failing one() clickhandler DEMO

Javascript

// I want to change "document" to ".menus" here
$(document).on("click", ".displayMenu", function(e)
{
    var $menu =  $(this).siblings(".menu");
    $(document).one("click", function(e2) 
       {
           if (e.target!=e2.target)
               $menu.hide(); 
       });
    $menu.toggle();
});​

HTML

<div class="menus">
    <div>
        <div class="displayMenu">Show menu 1</div>
        <div class="menu">menu 1</div>
    </div>
    <div>
        <div class="displayMenu">Show menu 2</div>
        <div class="menu">menu 2</div>
    </div>
</div>​
Jan
  • 5,688
  • 3
  • 27
  • 44
  • I checked **Succeeding propagation, failing one() clickhandler DEMO** but could not find how one() is failing in that ??? can you please elaborate more on that? – Tapan Nov 09 '12 at 07:28
  • Click one menu, then click the other. The first menu will not hide. – Jan Nov 09 '12 at 09:22
  • Just realized that `stopPropagation()` will prevent the `document.one()` event handler from triggering... Of course. *sigh* Thing is that even *without* `stopPropagation()`, `document.one()` fails... Any idea why? – Jan Nov 09 '12 at 09:29

1 Answers1

0

Thanks to @TapanC I realized I made an obvious mistake with stopPropagation(), of course it should prevent the document.one() event from triggering. I don't understand why document.one() still doesn't run even without stopPropagation() but here's a working solution.

Not entirely elegant though (I don't like the global hide() command) so any better suggestions appreciated! :)

Working (unpretty) solution DEMO

$(".menus").on("click", ".displayMenu", function(e)
{
    // Hide all
    $(".menu").hide();
    // Get current menu
    var $menu =  $(this).siblings(".menu").show();
    $(document).one("click", function(e2) 
       {
           if (e.target!=e2.target)
               $menu.hide(); 
       });
    // Prevent propagation
    e.stopPropagation();
});
Jan
  • 5,688
  • 3
  • 27
  • 44