Click outside menu to close in jquery

Jquery

Jquery Problem Overview


So I have a drop-down menu that shows on a click, as per business requirements. The menu becomes hidden again after you mouse away from it.

But now I am being asked to have it stay in place until user clicks anywhere on the document. How can this be accomplished?

This is a simplified version of what I have now:

$(document).ready(function() {
  $("ul.opMenu li").click(function(){
   $('#MainOptSubMenu',this).css('visibility', 'visible');
  });

  $("ul.opMenu li").mouseleave(function(){
      $('#MainOptSubMenu',this).css('visibility', 'hidden');
  });
});



<ul  class="opMenu">
  <li id="footwo" class="">
    <span id="optImg" style="display: inline-block;"> <img src="http://localhost.vmsinfo.com:8002/insight/images/options-hover2.gif"/> </span>
      <ul id="MainOptSubMenu" style="visibility: hidden; top: 25px; border-top: 0px solid rgb(217, 228, 250); background-color: rgb(217, 228, 250); padding-bottom: 15px;">
        <li>some</li>
       <li>nav</li>
       <li>links</li>
       </ul>
    </li>
</ul> 

I tried something like this $('document[id!=MainOptSubMenu]').click(function() thinking it would trigger on anything that wasnt the menu, but it didnt work.

Jquery Solutions


Solution 1 - Jquery

Take a look at the approach this question used:

https://stackoverflow.com/questions/152975/how-to-detect-a-click-outside-an-element

Attach a click event to the document body which closes the window. Attach a separate click event to the window which stops propagation to the document body.

$('html').click(function() {
  //Hide the menus if visible
});

$('#menucontainer').click(function(event){
    event.stopPropagation();
});

Solution 2 - Jquery

The answer is right, but it will add a listener that will be triggered every time a click occurs on your page. To avoid that, you can add the listener for just one time :

$('a#menu-link').on('click', function(e) {
    e.preventDefault();
    e.stopPropagation();

    $('#menu').toggleClass('open');

    $(document).one('click', function closeMenu (e){
        if($('#menu').has(e.target).length === 0){
            $('#menu').removeClass('open');
        } else {
            $(document).one('click', closeMenu);
        }
    });
});

Edit: if you want to avoid the stopPropagation() on the initial button you can use this

var $menu = $('#menu');

$('a#menu-link').on('click', function(e) {
    e.preventDefault();

    if (!$menu.hasClass('active')) {
        $menu.addClass('active');

        $(document).one('click', function closeTooltip(e) {
            if ($menu.has(e.target).length === 0 && $('a#menu-link').has(e.target).length === 0) {
                $menu.removeClass('active');
            } else if ($menu.hasClass('active')) {
                $(document).one('click', closeTooltip);
            }
        });
    } else {
        $menu.removeClass('active');
    }
});

Solution 3 - Jquery

The stopPropagation options are bad because they can interfere with other event handlers including other menus that might have attached close handlers to the HTML element.

Here is a simple solution based on user2989143's answer:

$('html').click(function(event) {
    if ($(event.target).closest('#menu-container, #menu-activator').length === 0) {
        $('#menu-container').hide();
    }
});

Solution 4 - Jquery

If using a plugin is ok in you case, then I suggest Ben Alman's clickoutside plugin located [here][1]:

its usage is as simple as this:

$('#menu').bind('clickoutside', function (event) {
    $(this).hide();
});

hope this helps. [1]: http://benalman.com/projects/jquery-outside-events-plugin/

Solution 5 - Jquery

2 options that you can investigate:

  • On showing of the menu, place a large empty DIV behind it covering up the rest of the page and give that an on-click event to close the menu (and itself). This is akin to the methods used with lightboxes where clicking on the background closes the lightbox
  • On showing of the menu, attach a one-time click event handler on the body that closes the menu. You use jQuery's '.one()' for this.

Solution 6 - Jquery

I found a variant of Grsmto's solution and Dennis' solution fixed my issue.

$(".MainNavContainer").click(function (event) {
    //event.preventDefault();  // Might cause problems depending on implementation
    event.stopPropagation();
    
    $(document).one('click', function (e) {
        if(!$(e.target).is('.MainNavContainer')) {
            // code to hide menus
        }
    });
});

Solution 7 - Jquery

what about this?

	$(this).mouseleave(function(){	
		var thisUI = $(this);
		$('html').click(function(){
		        thisUI.hide();
			$('html').unbind('click');
		 });
	 });

Solution 8 - Jquery

I use this solution with multiple elements with the same behavior in the same page:

$("html").click(function(event){
	var otarget = $(event.target);
	if (!otarget.parents('#id_of element').length && otarget.attr('id')!="id_of element" && !otarget.parents('#id_of_activator').length) {
		$('#id_of element').hide();
	}
});

stopPropagation() is a bad idea, this breaks standard behaviour of many things, including buttons and links.

Solution 9 - Jquery

I have recently faced the same issue. I wrote the following code:

    $('html').click(function(e) {
      var a = e.target;
      if ($(a).parents('.menu_container').length === 0) {
        $('.ofSubLevelLinks').removeClass('active'); //hide menu item
        $('.menu_container li > img').hide(); //hide dropdown image, if any
     }
    });

It has worked for me perfectly.

Solution 10 - Jquery

I find it more useful to use mousedown-event instead of click-event. The click-event doesn't work if the user clicks on other elements on the page with click-events. In combination with jQuery's one() method it looks like this:

$("ul.opMenu li").click(function(event){
   
   //event.stopPropagation(); not required any more
   $('#MainOptSubMenu').show();

   // add one mousedown event to html
   $('html').one('mousedown', function(){
       $('#MainOptSubMenu').hide();
   });
});

// mousedown must not be triggered inside menu
$("ul.opMenu li").bind('mousedown', function(evt){
    evt.stopPropagation();
});

Solution 11 - Jquery

even i came across the same situation and one of my mentor put this idea across to myself.

step:1 when clicked on the button on which we should show the drop down menu. then add the below class name "more_wrap_background" to the current active page like shown below

$('.ui-page-active').append("<div class='more_wrap_background' id='more-wrap-bg'> </div>");

step-2 then add a clicks for the div tag like

$(document).on('click', '#more-wrap-bg', hideDropDown);

where hideDropDown is the function to be called to hide drop down menu

Step-3 and important step while hiding the drop down menu is that remove that class you that added earlier like

$('#more-wrap-bg').remove();

I am removing by using its id in the above code

.more_wrap_background {
  top: 0;
  padding: 0;
  margin: 0;
  background: rgba(0, 0, 0, 0.1);
  position: fixed;
  display: block;
  width: 100% !important;
  z-index: 999;//should be one less than the drop down menu's z-index
  height: 100% !important;
}

Solution 12 - Jquery

$("html").click( onOutsideClick );
onOutsideClick = function( e )
{
	var t = $( e.target );
	if ( !(
		t.is("#mymenu" ) ||		//Where #mymenu - is a div container of your menu
		t.parents( "#mymenu" ).length > 0
		)	)
	{
		//TODO: hide your menu
	}
};

And better to set the listener only when your menu is being visible and always remove the listener after menu becomes hidden.

Solution 13 - Jquery

It doesn't have to be complicated.

$(document).on('click', function() {
	$("#menu:not(:hover)").hide();
});

Solution 14 - Jquery

I think you need something like this: http://jsfiddle.net/BeenYoung/BXaqW/3/

$(document).ready(function() {
  $("ul.opMenu li").each(function(){
      $(this).click(function(){
			if($(this).hasClass('opened')==false){			
                $('.opMenu').find('.opened').removeClass('opened').find('ul').slideUp();
				$(this).addClass('opened'); 
				$(this).find("ul").slideDown();
			}else{
				$(this).removeClass('opened'); 
				$(this).find("ul").slideUp();				
			}
      });
  });    
});

I hope it useful for you!

Solution 15 - Jquery

Use the ':visible' selector. Where .menuitem is the to-hide element(s) ...

$('body').click(function(){
  $('.menuitem:visible').hide('fast');
});

Or if you already have the .menuitem element(s) in a var ...

var menitems = $('.menuitem');
$('body').click(function(){
  menuitems.filter(':visible').hide('fast');
});

Solution 16 - Jquery

If you are not using jQuery and wanted to do it with pure CSS and HTML this is the solution.

  • Create a trigger element and inside it write your popup element.
  • Attach a click handler to unhide the popup on the click of the trigger element.
  • Have a backdrop element that stretches to the entire screen width and attach click handlers to that which hides the popup.
  • All attached click handlers should stop the event from propagating so other handlers are not called.

Find live code below

function showPopup(bShow,args){
  var popupContainer = document.getElementsByClassName('popup-container')[0];
  debugger;
  if(!bShow){
    popupContainer.classList.add('hide-element')
  }else{
    popupContainer.classList.remove('hide-element')
  }
  args[0].stopPropagation();
}

.popup-trigger{
  cursor: pointer;
  margin: 10px;
  padding: 5px;
  width: fit-content;
  background: red;
  border-radius: 5px;
  position: relative;
}

.body{
  width: 100%;
  height: 1000px;
  background: yellow;
  padding: 10px;
}

.backdrop{
  width: 100vw;
  height: 100vh;
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

.actual-popup{
}
.popup-container{
 top: 30px;
 width: 100px;
 height: 50px;
 background: grey;
 display: flex;
 justify-content: center;
 align-items: center;
 position: absolute;
}

.hide-element{
  visibility: hidden;
}

<div class="body">

  <div onclick="showPopup(true,arguments)" class="popup-trigger">Click to open dialog with button
    <div onclick="showPopup(false,arguments)" class='popup-container hide-element'> 
     <div onclick="showPopup(false,arguments)" class='backdrop'>  </div>
     <div onclick="showPopup(true,arguments)" class='actual-popup'> 
        <button onclick="showPopup(false,arguments)"> close me </button>
     </div>
     
    </div>
   
  </div>
</div>

Solution 17 - Jquery

Looks through these answers and this is how i ended up doing it

$('html').click(function(event) {

let openMenuButton = $("#menu-open");
let menu = $("#menu-popup");
let both = $('#menu-popup, #menu-open');

    if ( $(event.target).closest(both).length === 0 ) {  
        $(menu).hide();
        console.log("if statement");
        
    } else if ( $(menu).is(":visible") && $(event.target).closest(openMenuButton).length === 1 ){
    $(menu).hide();
    console.log("if ELSE statement");
    } else {
    $(menu).show();
    console.log("ELSE statement");
    }
   
});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGeorgeView Question on Stackoverflow
Solution 1 - JqueryJon WView Answer on Stackoverflow
Solution 2 - JqueryadriendenatView Answer on Stackoverflow
Solution 3 - JqueryCode CommanderView Answer on Stackoverflow
Solution 4 - JquerySubliminal HashView Answer on Stackoverflow
Solution 5 - JqueryDA.View Answer on Stackoverflow
Solution 6 - Jquerycat5devView Answer on Stackoverflow
Solution 7 - JquerycgfixView Answer on Stackoverflow
Solution 8 - Jqueryuser2989143View Answer on Stackoverflow
Solution 9 - JqueryNamishView Answer on Stackoverflow
Solution 10 - JqueryyeenoView Answer on Stackoverflow
Solution 11 - JqueryAbhimaanView Answer on Stackoverflow
Solution 12 - JqueryОлег ВсильдеревьевView Answer on Stackoverflow
Solution 13 - JqueryJonathan GaudéView Answer on Stackoverflow
Solution 14 - JquerySakata GintokiView Answer on Stackoverflow
Solution 15 - JqueryekernerView Answer on Stackoverflow
Solution 16 - JqueryAnandShivaView Answer on Stackoverflow
Solution 17 - Jquerykyle walkerView Answer on Stackoverflow