Reputation: 1144
I am copying the code and made possible change in w3schools code. The Dropdown 2, and Dropdown 3 button
is not working.
/* When the user clicks on the button,
toggle between hiding and showing the dropdown content */
function myFunction() {
document.getElementById("myDropdown").classList.toggle("show");
}
// Close the dropdown if the user clicks outside of it
window.onclick = function(e) {
if (!e.target.matches('.dropbtn')) {
var myDropdown = document.getElementById("myDropdown");
if (myDropdown.classList.contains('show')) {
myDropdown.classList.remove('show');
}
}
}
.navbar {
overflow: hidden;
background-color: #333;
font-family: Arial, Helvetica, sans-serif;
}
.navbar a {
float: left;
font-size: 16px;
color: white;
text-align: center;
padding: 14px 16px;
text-decoration: none;
}
.dropdown {
float: left;
overflow: hidden;
}
.dropdown .dropbtn {
cursor: pointer;
font-size: 16px;
border: none;
outline: none;
color: white;
padding: 14px 16px;
background-color: inherit;
font-family: inherit;
margin: 0;
}
.navbar a:hover, .dropdown:hover .dropbtn, .dropbtn:focus {
background-color: red;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
.dropdown-content a {
float: none;
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
text-align: left;
}
.dropdown-content a:hover {
background-color: #ddd;
}
.show {
display: block;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body>
<div class="navbar">
<div class="dropdown">
<button class="dropbtn" onclick="myFunction()">Dropdown 1
<i class="fa fa-caret-down"></i>
</button>
<div class="dropdown-content" id="myDropdown">
<a href="#">Link 1</a>
<a href="#">Link 2</a>
<a href="#">Link 3</a>
</div>
</div>
<div class="dropdown">
<button class="dropbtn" onclick="myFunction()">Dropdown 2
<i class="fa fa-caret-down"></i>
</button>
<div class="dropdown-content" id="myDropdown">
<a href="#">Link 1</a>
<a href="#">Link 2</a>
<a href="#">Link 3</a>
</div>
</div>
<div class="dropdown">
<button class="dropbtn" onclick="myFunction()">Dropdown 3
<i class="fa fa-caret-down"></i>
</button>
<div class="dropdown-content" id="myDropdown">
<a href="#">Link 1</a>
<a href="#">Link 2</a>
<a href="#">Link 3</a>
</div>
</div>
</div>
</body>
</html>
Upvotes: 0
Views: 975
Reputation: 65808
The problem is that all 3 of your drop downs have the same id
, which is not allowed. And since all 3 buttons use the same callback and that callback specifically toggles the visibility of that reused id
, the system stops when it finds the first matching element (because there should never be more than one element with the same id
in the first place).
The reality is that using id
s in the first place, while it seems like an easy approach, causes brittle code that doesn't scale (as you've found), so avoid id
s and use CSS classes and the hierarchy of your HTML elements as your methods for finding elements.
Also, never use getElementsByClassName()
or inline HTML event attributes.
Do yourself a favor and stay as far away from W3 Schools as you can as it is well-known to have incomplete, inaccurate, or just plain wrong information. Instead, you'll get much more comprehensive and up to date information from The Mozilla Developers Network (MDN), who are the stewards of the JavaScript language.
See the comments below for details:
// Set your events up in JavaScript, not with HTML event attributes
document.addEventListener("click", function(event) {
// Loop over all the menus
document.querySelectorAll(".dropdown-content").forEach(function(dd){
dd.classList.remove("show"); // Hide the menu
});
// If the clicked element was a button
if (event.target.classList.contains('dropbtn')) {
// Show just the menu that corresponds to the clicked button
event.target.nextElementSibling.classList.toggle("show");
}
});
.dropbtn {
background-color: #3498DB;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
.dropbtn:hover, .dropbtn:focus {
background-color: #2980B9;
}
.dropdown {
position: relative;
display: inline-block;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #f1f1f1;
min-width: 160px;
overflow: auto;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
.dropdown-content a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
}
.dropdown a:hover {background-color: #ddd;}
.show {display: block;}
<div class="dropdown">
<button class="dropbtn">Dropdown 1</button>
<div class="dropdown-content">
<a href="#home">Home 1</a>
<a href="#about">About 1</a>
<a href="#contact">Contact 1</a>
</div>
</div>
<div class="dropdown">
<button class="dropbtn">Dropdown 2</button>
<div class="dropdown-content">
<a href="#home">Home 2</a>
<a href="#about">About 2</a>
<a href="#contact">Contact 2</a>
</div>
</div>
<div class="dropdown">
<button class="dropbtn">Dropdown 3</button>
<div class="dropdown-content">
<a href="#home">Home 3</a>
<a href="#about">About 3</a>
<a href="#contact">Contact 3</a>
</div>
</div>
Upvotes: 3
Reputation: 22265
You can use .nextElementSibling ==> https://developer.mozilla.org/en-US/docs/Web/API/NonDocumentTypeChildNode/nextElementSibling
in your case
const allButtons = document.querySelectorAll('button.dropbtn');
allButtons.forEach(btn=>
{
btn.onclick=()=>{
allButtons.forEach(btn_X=>
{
let divContent = btn_X.nextElementSibling
if ( btn===btn_X) divContent.classList.toggle('show')
else divContent.classList.remove('show')
})
}
})
// Close the dropdown if the user clicks outside of it
window.onclick =e=>
{
if (e.target.matches('.dropbtn')) return
allButtons.forEach(btn=>btn.nextElementSibling.classList.remove('show'))
}
.dropbtn {
background-color: #3498DB;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
.dropbtn:hover, .dropbtn:focus {
background-color: #2980B9;
}
.dropdown {
position: relative;
display: inline-block;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #f1f1f1;
min-width: 160px;
overflow: auto;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
.dropdown-content a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
}
.dropdown a:hover {background-color: #ddd;}
.show {display: block; }
<div class="dropdown">
<button class="dropbtn">Dropdown 1</button>
<div class="dropdown-content">
<a href="#home">Home 1</a>
<a href="#about">About 1</a>
<a href="#contact">Contact 1</a>
</div>
</div>
<div class="dropdown">
<button class="dropbtn">Dropdown 2</button>
<div class="dropdown-content">
<a href="#home">Home 2</a>
<a href="#about">About 2</a>
<a href="#contact">Contact 2</a>
</div>
</div>
<div class="dropdown">
<button class="dropbtn">Dropdown 3</button>
<div class="dropdown-content">
<a href="#home">Home 3</a>
<a href="#about">About 3</a>
<a href="#contact">Contact 3</a>
</div>
</div>
Upvotes: 1
Reputation: 16150
You have to differentiate your menus somehow. I used a data-target
attribute. Also, you need to hide any visible menus before showing. About the button look, just change the css of .dropbtn
to your liking.
/* When the user clicks on the button,
toggle between hiding and showing the dropdown content */
function myFunction(el) {
var currentMenu = document.querySelector(".dropdown-content.show");
if (currentMenu) currentMenu.classList.toggle("show");
document.getElementById(el.dataset.target).classList.toggle("show");
}
// Close the dropdown if the user clicks outside of it
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');
}
}
}
}
.dropbtn {
background-color: #3498DB;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
.dropbtn:hover,
.dropbtn:focus {
background-color: #2980B9;
}
.dropdown {
position: relative;
display: inline-block;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #f1f1f1;
min-width: 160px;
overflow: auto;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
z-index: 1;
}
.dropdown-content a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
}
.dropdown a:hover {
background-color: #ddd;
}
.show {
display: block;
<div class="dropdown">
<button onclick="myFunction(this)" data-target="dropdown1" class="dropbtn">Dropdown 1</button>
<div id="dropdown1" class="dropdown-content">
<a href="#home">Home 1</a>
<a href="#about">About 1</a>
<a href="#contact">Contact 1</a>
</div>
</div>
<div class="dropdown">
<button onclick="myFunction(this)" data-target="dropdown2" class="dropbtn">Dropdown 2</button>
<div id="dropdown2" class="dropdown-content">
<a href="#home">Home 2</a>
<a href="#about">About 2</a>
<a href="#contact">Contact 2</a>
</div>
</div>
<div class="dropdown">
<button onclick="myFunction(this)" data-target="dropdown3" class="dropbtn">Dropdown 3</button>
<div id="dropdown3" class="dropdown-content">
<a href="#home">Home 3</a>
<a href="#about">About 3</a>
<a href="#contact">Contact 3</a>
</div>
</div>
Upvotes: 1