Carl Edwards
Carl Edwards

Reputation: 14434

Mouseup event conflict with visibility toggle

I've created a function that toggles a menu based on its' visibility. I also assigned a mouseup event to the document where the menu closes if the user clicks anywhere outside of it. The problem is when the mouseup event listener is added for the document the toggle no longer works. The visibility test: $menu.is(":visible"); returns false despite the menu being in plain sight. What's going on here?

$(function() {
  var $toggleMenu = $(".toggle-menu"),
      $menu = $(".menu");
    
  $toggleMenu.on("click", function(e) {
    e.preventDefault();
		
    toggleUserMenu();
  });
  
  $(document).on("mouseup", function (e) {
      
    if (!$menu.is(e.target) && $menu.has(e.target).length === 0) {
      $menu.hide();
    }
  });

  function toggleUserMenu() {
    var menuIsVisible = $menu.is(":visible");

    if (menuIsVisible) {
	  $menu.hide();
	} else {
      $menu.show();
	}
  }
});
.toggle-menu {
  color: #444;
  display: inline-block;
  margin-bottom: 15px;
  text-decoration: none;
}

.menu {
  border: 1px solid black;
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<a href="" class="toggle-menu">Toggle Menu</a>

<div class="menu">
  <a href="#" class="menu-item">Menu Item 1</a>
  <a href="#" class="menu-item">Menu Item 2</a>
  <a href="#" class="menu-item">Menu Item 3</a>
</div>

Upvotes: 0

Views: 255

Answers (2)

sabithpocker
sabithpocker

Reputation: 15566

One solution can be by preventing the mouseup in the conflicting area to bubble up.

$(function() {
  var $toggleMenu = $(".toggle-menu"),
      $menu = $(".menu");

  $toggleMenu.on("click", function(e) {
    e.preventDefault();

    toggleUserMenu();
  });

  $toggleMenu.on("mouseup", function(e) {
    e.preventDefault();
    e.stopPropagation();
  });

  $(document).on("mouseup", function (e) {

    if (!$menu.is(e.target) && $menu.has(e.target).length === 0) {
      $menu.hide();
    }
  });

  function toggleUserMenu() {
    var menuIsVisible = $menu.is(":visible");
console.log(menuIsVisible);
    if (menuIsVisible) {
      $menu.hide();
    } else {
      $menu.show();
    }
  }
});

  $toggleMenu.on("mouseup", function(e) {
    e.preventDefault();
    e.stopPropagation();
  });

This will catch the mouseup that is fired along with the click on Toggle Button and stops it from bubbling up to document. preventDefault() doesn't have any specific purpose here, It came with your code that I copied :)

Here is a fiddle

Upvotes: 1

Omidam81
Omidam81

Reputation: 1917

you run $menu.hide twice and it is problem.

$(function() {
  var $toggleMenu = $(".toggle-menu"),
      $menu = $(".menu");
    
  $toggleMenu.on("click", function(e) {
    e.preventDefault();
		
    toggleUserMenu();
  });
  
  $(document).on("mouseup", function (e) {
    console.log("Event is still firing");
      
    if (!$menu.is(e.target) && $menu.has(e.target).length === 0) {
      //if you commment this the code work.
      // $menu.hide();
    }
});

  function toggleUserMenu() {
    var menuIsVisible = $menu.is(":visible");

    if (menuIsVisible) {
	  $menu.hide();
	} else {
      $menu.show();
	}
  }
});
.toggle-menu {
  color: #444;
  display: inline-block;
  margin-bottom: 15px;
  text-decoration: none;
}

.menu {
  border: 1px solid black;
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<a href="" class="toggle-menu">Toggle Menu</a>

<div class="menu">
  <a href="#" class="menu-item">Menu Item 1</a>
  <a href="#" class="menu-item">Menu Item 2</a>
  <a href="#" class="menu-item">Menu Item 3</a>
</div>

Upvotes: 0

Related Questions