I do not think this is a duplicate question. I have tried some of the other solutions found on this website without the resolve I am looking for. How do I detect a click outside an element? for example uses event.stopPropagation();
and does not function with multiple menus correctly for me.
What I am trying to accomplish is, when a user clicks anywhere outside of a drop down menu that is open, the open menu will close.
I like the way the javascript code functions from w3schools.com, it does what I am looking for, however I am missing what I need for input into the window.onclick = function (event){
to adapt it into my code structure.
This is a sample file that I have put together to highlight what I am trying to implement.
<!DOCTYPE html>
<html>
<head>
<style>
li > ul{display:none;}
.show {display:block;}
.sub-nav ul {
background: #efefef;
background: linear-gradient(top, #efefef 0%, #bbbbbb 100%);
background: -moz-linear-gradient(top, #efefef 0%, #bbbbbb 100%);
background: -webkit-linear-gradient(top, #efefef 0%,#bbbbbb 100%);
box-shadow: 0px 0px 9px rgba(0,0,0,0.15);
padding: 0 20px;
border-radius: 0px;
list-style: none;
position: relative;
}
.sub-nav ul:after {content: ""; clear: both; display: block;}
li {float: left;}
.sub-nav ul li:hover {
background: #4b545f;
background: linear-gradient(top, #4f5964 0%, #5f6975 40%);
background: -moz-linear-gradient(top, #4f5964 0%, #5f6975 40%);
background: -webkit-linear-gradient(top, #4f5964 0%,#5f6975 40%);
}
.sub-nav ul li:hover a {color: #fff;}
.sub-nav ul li a {
display: block;
padding: 20px 40px;
color: #757575;
text-decoration: none;
}
.sub-nav ul ul {
background: #5f6975;
border-radius: 0px;
padding: 0;
position: absolute;
top: 100%;
}
.sub-nav ul ul li {
float: none;
border-top: 1px solid #6b727c;
border-bottom: 1px solid #575f6a;
position: relative;
}
.sub-nav ul ul li a {padding: 15px 40px; color: #fff;}
.sub-nav ul ul li a:hover {background: #4b545f;}
</style>
</head>
<body>
<!-- START: nav -->
<div class="sub-nav">
<div class="container">
<ul>
<li class="active"><a href="#">ROOT 1</a></li>
<li><a href="#">ROOT 2</a></li>
<li><a href="#">ROOT 3</a></li>
<li><a href="#">ROOT 4</a></li>
<li><a href="#">ROOT 5</a></li>
<li id="drop-one"><a href="#">DROP 1</a>
<ul>
<li class="has-sub"><a href="#">SUB MENU 1</a></li>
<li class="has-sub"><a href="#">SUB MENU 2</a></li>
<li class="has-sub"><a href="#">SUB MENU 3</a></li>
<li class="has-sub"><a href="#">SUB MENU 4</a></li>
</ul>
</li>
<li id="drop-two"><a>DROP 2</a>
<ul>
<li class="has-sub"><a href="#">SUB MENU LONG TITLE 1</a></li>
<li class="has-sub"><a href="#">SUB MENU LONG TITLE 2</a></li>
<li class="has-sub"><a href="#">SUB MENU LONG TITLE 3</a></li>
</ul>
</li>
</ul>
</div>
</div>
<!-- END: nav -->
</body>
</html>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
jQuery("li:has(ul)").click(function(){
jQuery("ul",this).toggleClass("show");
});
window.onclick = function(event) {
if (!event.target.matches('??????')) {
var dropdowns = document.getElementsByClassName("??????");
var i;
for (i=0; i<dropdowns.length; i++) {
var openDropdown = dropdowns[i];
if (openDropdown.classList.contains('show')) {
openDropdown.classList.remove('show');
}
}
}
}
</script>
To be as specific as I can what should I replace "??????" with to make this script work. If the html code needs to be modified to make this script work please advise, thank you!
window.onclick = function(event) {
if (!event.target.matches('??????')) {
var dropdowns = document.getElementsByClassName("??????");
var i;
for (i=0; i<dropdowns.length; i++) {
var openDropdown = dropdowns[i];
if (openDropdown.classList.contains('show')) {
openDropdown.classList.remove('show');
}
}
}
}
UPDATE: 12/27/2016 Just to follow up, I was able to come up with what I think are the needed modifications to achieve what was needed.
First I added li, and ul classes "dropdown" and "is-open" respectively.
<li class="dropdown"><a href="#">DROP 1</a>
<ul class="is-open">
<li><a href="#">SUB MENU 1</a></li>
<li><a href="#">SUB MENU 2</a></li>
<li><a href="#">SUB MENU 3</a></li>
<li><a href="#">SUB MENU 4</a></li>
</ul>
</li>
<li class="dropdown"><a href="#">DROP 2</a>
<ul class="is-open">
<li><a href="#">SUB MENU LONG TITLE 1</a></li>
<li><a href="#">SUB MENU LONG TITLE 2</a></li>
<li><a href="#">SUB MENU LONG TITLE 3</a></li>
</ul>
</li>
Second I replaced the previous script with:
<script>
// this is the function caller for click into drop down menu
$(document).ready(function(){
// this to function call targets the drop down menu by elements
$("li:has(ul)").click(function(){
// (IMPORTANT) code to hide existing open drop down menu before displaying new drop down menu
$(".is-open").hide();
// code to toggle menu from drop down ROOT
$(this).find(".is-open").toggle();
});// END: .click
});// END: .ready
//this script closes menu when clicked outside of drop down menu.
$(document).on("click", function(event){
var $triggerOn = $(".dropdown");
if($triggerOn !== event.target && !$triggerOn.has(event.target).length){
$(".is-open").hide();
}// END: if statement
});// END: .on
</script>
This has allowed me to implement what I desired in terms of clicking outside of the drop down menu, and the menu closes.
I now have created only one remaining issue with clicking on the "DROP x" root level. The menu will expand on click, but a second click on the root level will no longer close the drop down menu. Any advice to resolving this?
(Note: If I remove $(".is-open").hide();
from the script it restores the click to open and click to close functionality, however when clicking from "DROP 1" to "DROP 2" the drop down menus will stay open.)