I need the help with Javascript onclick
Dropdown Menu.
The menu opens when I click the button and closes when I click outside.
The problem is that when I open one menu and click on another, the previous menu stays open.
I want the solution that when I open one menu when I open another menu the previous menu closes.
<!DOCTYPE HTML>
<html>
<head>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
}
.navbar {
width: 100%;
padding: 0 10% 0 10%;
overflow: hidden;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
}
.dropbtn {
font-size: 16px;
border: none;
outline: none;
padding: 21.5px 20px;
background-color: inherit;
margin: 0;
cursor: pointer;
font-weight: bolder;
color: #2d3436;
}
.dropdown {
float: left;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #fff;
min-width: 460px;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
height: 450px;
}
.show {
display: block
}
</style>
</head>
<body>
<div class="navbar">
<div class="dropdown">
<button onclick="my1Function()" class="dropbtn dropbtn1">Dropdown <i class="fas fa-caret-down"></i></button>
<div id="myDropdown1" class="dropdown-content dropdown-content1">
</div>
</div>
<div class="dropdown">
<button onclick="my2Function()" class="dropbtn dropbtn2">Dropdown <i class="fas fa-caret-down"></i></button>
<div id="myDropdown2" class="dropdown-content dropdown-content2">
</div>
</div>
<div class="dropdown">
<button onclick="my3Function()" class="dropbtn dropbtn3">Dropdown <i class="fas fa-caret-down"></i></button>
<div id="myDropdown3" class="dropdown-content dropdown-content2">
</div>
</div>
</div>
<script>
function my1Function() {
document.getElementById("myDropdown1").classList.toggle("show");
}
function my2Function() {
document.getElementById("myDropdown2").classList.toggle("show");
}
function my3Function() {
document.getElementById("myDropdown3").classList.toggle("show");
}
window.onclick = function(event) {
if (!event.target.matches('.dropbtn')) {
var dropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < dropdowns.length; i ) {
var openDropdown = dropdowns[i];
if (openDropdown.classList.contains('show')) {
openDropdown.classList.remove('show');
}
}
}
}
</script>
</body>
</html>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
You may not need specific onclick
event like my1Function
for each dropdown button, instead use a generic event listener.
- Hide any open dropdown content. (This takes care of hiding the dropdown content when clicked outside)
- Show the dropdown content specific to the clicked button.
<!DOCTYPE HTML>
<html>
<head>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
}
.navbar {
width: 100%;
padding: 0 10% 0 10%;
overflow: hidden;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
}
.dropbtn {
font-size: 16px;
border: none;
outline: none;
padding: 21.5px 20px;
background-color: inherit;
margin: 0;
cursor: pointer;
font-weight: bolder;
color: #2d3436;
}
.dropdown {
float: left;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #fff;
min-width: 460px;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
height: 450px;
}
.show {
display: block
}
</style>
</head>
<body>
<div class="navbar">
<div class="dropdown">
<button class="dropbtn dropbtn1">Dropdown 1<i class="fas fa-caret-down"></i></button>
<div id="myDropdown1" class="dropdown-content dropdown-content1">
</div>
</div>
<div class="dropdown">
<button class="dropbtn dropbtn2">Dropdown 2<i class="fas fa-caret-down"></i></button>
<div id="myDropdown2" class="dropdown-content dropdown-content2">
</div>
</div>
<div class="dropdown">
<button class="dropbtn dropbtn3">Dropdown 3<i class="fas fa-caret-down"></i></button>
<div id="myDropdown3" class="dropdown-content dropdown-content2">
</div>
</div>
</div>
<script>
window.addEventListener('click', function(event) {
// Hide any open dropdown content
const dropdownContents = document.querySelectorAll('.dropdown-content')
dropdownContents.forEach(content => {
content.classList.remove('show');
});
// Show the dropdown content respective to the clicked button
if (event.target.matches('.dropbtn')) {
event.target.nextElementSibling.classList.add('show');
}
})
</script>
</body>
</html>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
I would do the dropdown as a details tag like this:
<nav>
<ul class="my-nav">
<li>
<details class="dropdown">
<summary>This has dropdown items</summary>
<ul>
<li><a href="#hi">Hi</a></li>
<li><a href="#universe">Universe</a></li>
</ul>
</details>
</li>
<li>
<details class="dropdown">
<summary>Another dropdown</summary>
<ul>
<li><a href="#goodbye">Goodbye</a></li>
<li><a href="#universe">Universe</a></li>
</ul>
</details>
</li>
</ul>
</nav>
Granted you would have different summaries/links, and here is the corresponding js:
var nav = document.querySelector('.my-nav');
nav.addEventListener('toggle', function (event) {
// Only run if the dropdown is open
if (!event.target.open) return;
// Get all other open dropdowns and close them
var dropdowns = nav.querySelectorAll('.dropdown[open]');
Array.prototype.forEach.call(dropdowns, function (dropdown) {
if (dropdown === event.target) return;
dropdown.removeAttribute('open');
});
}, true);