Dropdowns to Collapse when clicking outside - javascript

I am a newbie in coding and I wonder if it's possible to create multiple dropdown menus, and whenever you click outside an opened box, I want it to be collapsed. I am sharing the code I wrote but it's not working since one dropdown is collapsing when clicking outside, but the other one isn't. Can you help me with that? I'm sharing the code and I want 3 dropdown menus. I'm struggling with this for weeks now and I haven't succeeded yet. Thanks in advance!
HTML Code
<div class="container">
<span class="Agencymenu">Home</span>
<span class="Agencymenu">News</span>
<div class="dropdown">
<button class="dropbtn" onclick="myFunction()">Team 1</button>
<div class="dropdown-content" id="myDropdown">
<span class="Agencymenu">Link 1</span>
<span class="Agencymenu">Link 2</span>
<span class="Agencymenu">Link 3</span>
</div>
</div>
<div class="dropdown2">
<button class="dropbtn2" onclick="myFunction2()">Team 2</button>
<div class="dropdown-content2" id="myDropdown2">
<span class="Agencymenu">Link 1</span>
<span class="Agencymenu">Link 2</span>
<span class="Agencymenu">Link 3</span>
</div>
</div>
</div>
CSS Code
.Agencymenu {
font-family: 'AGENCYB' !important;
font-weight: bold;
font-size: 24pt;
color: #FFFFFF;
}
.container {
overflow: hidden;
background-color: #30333c;
font-family: Arial;
}
.container 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:AGENCYB;
font-size:30px;
}
.container a:hover, .dropdown:hover .dropbtn {
background-color: #0C0;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #30333c;
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;
}
.container2 {
overflow: hidden;
background-color: #30333c;
font-family: Arial;
}
.container2 a {
float: left;
font-size: 16px;
color: white;
text-align: center;
padding: 14px 16px;
text-decoration: none;
}
.dropdown2 {
float: left;
overflow: hidden;
}
.dropdown2 .dropbtn2 {
cursor: pointer;
font-size: 16px;
border: none;
outline: none;
color: white;
padding: 14px 16px;
background-color: inherit;
font-family:AGENCYB;
font-size:30px;
}
.container2 a:hover, .dropdown2:hover .dropbtn2 {
background-color: #0C0;
}
.dropdown-content2 {
display: none;
position: absolute;
background-color: #30333c;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
.dropdown-content2 a {
float: none;
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
text-align: left;
}
.dropdown-content2 a:hover {
background-color: #0C0;
}
.show2 {
display: block;
}
JS Code:
/* When the user clicks on the button,
toggle between hiding and showing the dropdown content */
function myFunction() {
document.getElementById("myDropdown").classList.toggle("show2");
}
// 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('show2')) {
myDropdown.classList.remove('show2');
}
}
}
/* When the user clicks on the button,
toggle between hiding and showing the dropdown content */
function myFunction2() {
document.getElementById("myDropdown2").classList.toggle("show2");
}
// Close the dropdown if the user clicks outside of it
window.onclick = function(e) {
if (!e.target.matches('.dropbtn2')) {
var myDropdown2 = document.getElementById("myDropdown2");
if (myDropdown2.classList.contains('show2')) {
myDropdown2.classList.remove('show2');
}
}
}

if you are okay using CSS only solution and you need dropdown on hover, you can simply use this code
.dropdown:hover .dropdown-content {display: block}
here is the fiddle https://jsfiddle.net/hkred6d7/1/
if you need it on click, let me know here in comment. it will require JS

It would be a lot easier with jQuery, but here is an example with vanilla JS. The key here is to reuse a css class for all dropdowns
https://jsfiddle.net/fyjjzhqw/
//HTML
<body>
<div class="wrapper">
<div class="Dropdown">
<div class="Dropdown__btn">Dropdown 1</div>
<ul class="Dropdown__list">
<li>Item A</li>
<li>Item B</li>
<li>Item C</li>
</ul>
</div>
<div class="Dropdown">
<div class="Dropdown__btn">Dropdown 2</div>
<ul class="Dropdown__list">
<li>Item A</li>
<li>Item B</li>
<li>Item C</li>
</ul>
</div>
<div class="Dropdown">
<div class="Dropdown__btn">Dropdown 3</div>
<ul class="Dropdown__list">
<li>Item A</li>
<li>Item B</li>
<li>Item C</li>
</ul>
</div>
</div>
</body>
// CSS
.Dropdown__list {
display: none
}
.is-opened.Dropdown .Dropdown__list {
display: block
}
//JS
var dropdowns = document.querySelectorAll('.Dropdown');
var closeAll = function() {
dropdowns.forEach( function(current) {
current.classList.remove('is-opened')
})
}
var toggleDropdown = function(e) {
closeAll();
var dropdown = e.currentTarget.parentElement;
dropdown.classList.toggle('is-opened')
}
for (i = dropdowns.length - 1; i >= 0; i--) {
dropdowns[i].querySelector('.Dropdown__btn').addEventListener('click', toggleDropdown)
}

you can try using this https://jsfiddle.net/aswin_89/hkred6d7/9/
modified your JS a bit
/* When the user clicks on the button,
toggle between hiding and showing the dropdown content */
function myFunction() {
event.target.nextElementSibling.classList.toggle("show2");
}
function clearClasses (target){
document.querySelectorAll('.dropdown-content.show2').forEach((item)=>{
if(event.target.nextElementSibling !== item)
item.classList.remove('show2');
})
}
// Close the dropdown if the user clicks outside of it
window.onclick = function(e) {
clearClasses(event.target.nextElementSibling);
}

Related

I have three drop down button I want to click the specific dropdown and pop up the list and display on the that specific click dropdown , not in all

I have three drop down button that I style them using the same class. When I click any of them it pops up a list where I select any list under the dropdown and display it on the button.
The problem is that it's displaying in all of the three dropdowns even though I focus on the specific drop down and I am voiding to have along code by changing each an every dropdown an ID and target on it. If there's away to do it may you please help.
.dropdownbox>button {
color: #7C99AA;
background-color: white;
border: 1px solid #7C99AA;
border-radius: 0.5em;
padding: 0.7em 1em;
width: 10vw;
font-size: 12px;
line-height: 1.4em;
user-select: none;
cursor: pointer;
text-indent: 1px;
text-overflow: '';
text-align: center;
outline: none;
text-align: center;
}
ul.menu {
list-style: none;
position: absolute;
margin: 0 auto;
width: 8vw;
overflow: hidden;
height: 0px;
margin-top: 2px;
background: white;
color: #9FA5B5;
border-radius: 10px;
cursor: pointer;
box-shadow: 0 0.5em 1em rgb(0, 0, 0, 0.2);
padding: 5px 20;
position: absolute;
}
ul.menu li {
font-size: 16px;
padding: 0.7em 0em;
margin: -0.3em 0;
border-radius: 0.5em;
cursor: pointer;
}
ul.menu li:hover {
color: white;
background: #7C99AA;
}
.menu.showMenu {
height: 20vh;
}
<div class="wrapCollect3">
<div class="dropdownbox">
<button class="dropbtn" id="penaltybtn">Select</button>
</div>
<ul id="menu3" class="menu">
<li id="applicc">Not Applicable</li>
<li id="appYes">Yes</li>
<li id="appNo">No</li>
</ul>
</div>
<div class="wrapper">
<div class="dropdownbox">
<button class="dropbtn" id="offboarding">Select</button>
</div>
<ul id="menu1" class="menu">
<li name="offboarding" id="resignation">Resignation</li>
<li name="offboarding" id="contract">Contract Expiration</li>
<li name="offboarding" id="retrenchment">Retrenchment</li>
<li name="offboarding" id="dismissal">Dismissal</li>
<li name="offboarding" id="retirement">Retirement</li>
</ul>
</div>
<div class="collecWrap">
<div class="dropdownbox">
<button class="dropbtn" id="dropbtn">Collected</button>
</div>
<ul id="menu2" class="menu">
<li id="returnNot" value="NotReturned">Not Returned</li>
<li id="majority" value="majority">Majority Returned</li>
<li id="all">All Returned</li>
</ul>
</div>
You can try it like this:
$('.dropdownbox').click(function() {
$('.menu').hide();
$(this).next('.menu').show();
});
I've also changed your css a little bit. I've removed height:0px from ul.menu and added display:none;
$('.dropdownbox').click(function() {
$('.menu').hide();
$(this).next('.menu').show();
});
.dropdownbox>button {
color: #7C99AA;
background-color: white;
border: 1px solid #7C99AA;
border-radius: 0.5em;
padding: 0.7em 1em;
width: 10vw;
font-size: 12px;
line-height: 1.4em;
user-select: none;
cursor: pointer;
text-indent: 1px;
text-overflow: '';
text-align: center;
outline: none;
text-align: center;
}
ul.menu {
list-style: none;
position: absolute;
margin: 0 auto;
width: 8vw;
overflow: hidden;
margin-top: 2px;
background: white;
color: #9FA5B5;
border-radius: 10px;
cursor: pointer;
box-shadow: 0 0.5em 1em rgb(0, 0, 0, 0.2);
padding: 5px 20px;
position: absolute;
display:none;
}
ul.menu li {
font-size: 16px;
padding: 0.7em 0em;
margin: -0.3em 0;
border-radius: 0.5em;
cursor: pointer;
}
ul.menu li:hover {
color: white;
background: #7C99AA;
}
.menu.showMenu {
height: 20vh;
}
.wrapper,.wrapCollect3,.collectWrap{
display: inline-block;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapCollect3">
<div class="dropdownbox">
<button class="dropbtn" id="penaltybtn">Select</button>
</div>
<ul id="menu3" class="menu">
<li id="applicc">Not Applicable</li>
<li id="appYes">Yes</li>
<li id="appNo">No</li>
</ul>
</div>
<div class="wrapper">
<div class="dropdownbox">
<button class="dropbtn" id="offboarding">Select</button>
</div>
<ul id="menu1" class="menu">
<li name="offboarding" id="resignation">Resignation</li>
<li name="offboarding" id="contract">Contract Expiration</li>
<li name="offboarding" id="retrenchment">Retrenchment</li>
<li name="offboarding" id="dismissal">Dismissal</li>
<li name="offboarding" id="retirement">Retirement</li>
</ul>
</div>
<div class="collecWrap">
<div class="dropdownbox">
<button class="dropbtn" id="dropbtn">Collected</button>
</div>
<ul id="menu2" class="menu">
<li id="returnNot" value="NotReturned">Not Returned</li>
<li id="majority" value="majority">Majority Returned</li>
<li id="all">All Returned</li>
</ul>
</div>
You are not too clear in your answer, and you are providing no working code,
But If I get it, you need to show on the button the text you click in the submenu, like "emulating a select".
It's quite easy.
So, on the 3 main parents add a class
<div class="wrapCollect3 buttonParent">
[...]
<div class="wrapper buttonParent">
[...]
<div class="collecWrap buttonParent">
In js, add a function to retrieve them on click
function getParentByClass(el, className, maxDepth=10) {
let i=0;
while (!el.classList.contains(className)) {
el=el.parentElement;
i++;
if (i>maxDepth) return false;
}
return el;
}
call it like this:
// In your onclick function,
// given "el" as the clicked submenu button
let parent = getParentByClass(el, "buttonParent")
Now find the button inside the buttonParent of the clicked submenu, and set its text as the text you clicked in the submenu
parent.querySelector('button').innerText = el.getText();
Now you just need to fix the "hide" submenu when you click outside the submenu. I leave this exercise to you, because this is not "code solution" website, and we are here always to learn! Cheers!
/// Taken from Carsten Løvbo Andersen answer
$('.dropdownbox').click(function() {
$('.menu').hide();
$(this).next('.menu').show();
});
//// Maybe there is some jquery version, but this is universal
/// this find parent by class name, giving a depth in search too
function getParentByClass(el, className, maxDepth=10) {
let i=0;
while (!el.classList.contains(className)) {
el=el.parentElement;
i++;
if (i>maxDepth) return false;
}
return el;
}
document.querySelectorAll("ul.menu li").forEach(function(el){
el.addEventListener('click', function(c){
let li = c.target;
let t = li.innerText;
let p = getParentByClass(li, 'parentButton');
p.querySelector('button').innerText = t;
$('.menu').hide();
});
});
.dropdownbox>button {
color: #7C99AA;
background-color: white;
border: 1px solid #7C99AA;
border-radius: 0.5em;
padding: 0.7em 1em;
width: 10vw;
font-size: 12px;
line-height: 1.4em;
user-select: none;
cursor: pointer;
text-indent: 1px;
text-overflow: '';
text-align: center;
outline: none;
text-align: center;
}
ul.menu {
list-style: none;
position: absolute;
margin: 0 auto;
width: 8vw;
overflow: hidden;
margin-top: 2px;
background: white;
color: #9FA5B5;
border-radius: 10px;
cursor: pointer;
box-shadow: 0 0.5em 1em rgb(0, 0, 0, 0.2);
padding: 5px 20px;
position: absolute;
display:none;
}
ul.menu li {
font-size: 16px;
padding: 0.7em 0em;
margin: -0.3em 0;
border-radius: 0.5em;
cursor: pointer;
}
ul.menu li:hover {
color: white;
background: #7C99AA;
}
.menu.showMenu {
height: 20vh;
}
.wrapper,.wrapCollect3,.collectWrap{
display: inline-block;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapCollect3 parentButton">
<div class="dropdownbox">
<button class="dropbtn" id="penaltybtn">Select</button>
</div>
<ul id="menu3" class="menu">
<li id="applicc">Not Applicable</li>
<li id="appYes">Yes</li>
<li id="appNo">No</li>
</ul>
</div>
<div class="wrapper parentButton">
<div class="dropdownbox">
<button class="dropbtn" id="offboarding">Select</button>
</div>
<ul id="menu1" class="menu">
<li name="offboarding" id="resignation">Resignation</li>
<li name="offboarding" id="contract">Contract Expiration</li>
<li name="offboarding" id="retrenchment">Retrenchment</li>
<li name="offboarding" id="dismissal">Dismissal</li>
<li name="offboarding" id="retirement">Retirement</li>
</ul>
</div>
<div class="collecWrap parentButton">
<div class="dropdownbox">
<button class="dropbtn" id="dropbtn">Collected</button>
</div>
<ul id="menu2" class="menu">
<li id="returnNot" value="NotReturned">Not Returned</li>
<li id="majority" value="majority">Majority Returned</li>
<li id="all">All Returned</li>
</ul>
</div>

How do I manipulate the javascript code to have three different dropdown menus in my navbar which don't interfere with each other?

I have one dropdown working, but the second dropdown interferes with the first one. Still very new to JavaScript and don't have time to learn it properly at the moment, so help is much appreciated!
Dropdown CSS
.dropdown{
display:inline-block;
}
.dropdown .dropbtn {
cursor: pointer;
font-size: 100%;
border: none;
outline: none;
color: white;
padding: 10px 20px;
background-color: inherit;
font-family: inherit;
margin: 0;
}
.navbar a:hover, .dropdown:hover .dropbtn, .dropbtn:focus {
background-color: #FFA036;
color:black;
}
.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;
border:1px solid black;
}
.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;
}
Navigation bar HTML
I have one dropdown working well, but as soon as I put a second one in, it interferes with the first. I also have links in the bar which don't need dropdowns.
<nav>
Link
<div class="dropdown">
<button class="dropbtn" onclick="myFunction()"> Link
</button>
<div class="dropdown-content" id="myDropdown">
Link
Link
Link
Link
Link
Link
Link
Link
Link
</div>
</div>
<div class="dropdown">
<button class="dropbtn" onclick="myFunction()"> Link
</button>
<div class="dropdown-content" id="myDropdown">
Link
Link
Link
Link
</div>
</div>
Link
Link
Link
<a href="Link"> Link
</a>
</nav>
JavaScript
I think what is going wrong is something in the JavaScript here. A simple fix to make the JavaScript apply to all dropdowns would be great!
<script>
function myFunction() {
document.getElementById("myDropdown").classList.toggle("show");
}
window.onclick = function(e) {
if (!e.target.matches('.dropbtn')) {
var myDropdown = document.getElementById("myDropdown");
if (myDropdown.classList.contains('show')) {
myDropdown.classList.remove('show');
}
}
}
</script>
function myFunction(event) {
var parentDiv = event.target.parentNode;
var currentDropdown = parentDiv.querySelector(".dropdown-content");
currentDropdown.classList.toggle("show");
var dropdownContent = document.querySelectorAll(".dropdown .dropdown-content");
dropdownContent.forEach(function (dropdownContentItem) {
if (currentDropdown != dropdownContentItem) {
dropdownContentItem.classList.remove("show");
}
})
}
window.onclick = function (e) {
if (!e.target.parentNode.classList.contains('dropdown')) {
var dropdownContent = document.querySelectorAll(".dropdown .dropdown-content");
dropdownContent.forEach(function (dropdownContentItem) {
dropdownContentItem.classList.remove("show");
})
}
}
<nav>
Link
<div class="dropdown">
<button class="dropbtn" onclick="myFunction(event)"> Link
</button>
<div class="dropdown-content" id="myDropdown">
Link
Link
Link
Link
Link
Link
Link
Link
Link
</div>
</div>
<div class="dropdown">
<button class="dropbtn" onclick="myFunction(event)"> Link
</button>
<div class="dropdown-content" id="myDropdown">
Link
Link
Link
Link
</div>
</div>
Link
Link
Link
<a href="Link"> Link
</a>
</nav>
You can't use identical IDs for multiple elements.
var prevMenu = null; //we will store last opened menu here
function myFunction(link)
{
var menu = link.parentNode.getElementsByClassName("dropdown-content")[0];
if (!menu)
return;
if (prevMenu && prevMenu !== menu)
prevMenu.classList.remove('show'); //close previous menu
prevMenu = menu;
menu.classList.toggle("show");
}
window.onclick = function(e) {
if (!e.target.matches('.dropbtn') && prevMenu) {
prevMenu.classList.remove('show');
}
}
.dropdown
{display:inline-block;
}
.dropdown .dropbtn {
cursor: pointer;
font-size: 100%;
border: none;
outline: none;
color: black;
padding: 10px 20px;
background-color: inherit;
font-family: inherit;
margin: 0;
}
.navbar a:hover, .dropdown:hover .dropbtn, .dropbtn:focus {
background-color: #FFA036;
color:black;
}
.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;
border:1px solid black;
}
.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;
}
<nav>
Link
<div class="dropdown">
<button class="dropbtn" onclick="myFunction(this)"> Link1
</button>
<div class="dropdown-content">
sub Link 1.1
sub Link 1.2
sub Link 1.3
</div>
</div>
<div class="dropdown">
<button class="dropbtn" onclick="myFunction(this)"> Link2
</button>
<div class="dropdown-content">
sub Link 2.1
sub Link 2.2
sub Link 2.3
</div>
</div>
Link
Link
Link
<a href="Link"> Link
</a>
</nav>

Navigation bar has whitespace above it [duplicate]

This question already has answers here:
How wide is the default `<body>` margin?
(4 answers)
What are the default margins for the html heading tags (<h1>, <h2>, <h3>, etc.)?
(4 answers)
Closed 2 years ago.
I am designing a website, as I am adding clickable button to it. My Nav-bar having some white-space above it.
Previously I have posted same question, but now I don't know what's wrong with my CSS. Please rectify or mention where my CSS is done wrong. I donot want to render my navbar, with white space above it.
So, Please change the CSS, and show me where I am doing error.
I also added css icon to it. As I
function myFunction(event) {
var clickedElement = event.target;
console.log(clickedElement);
if (clickedElement.nodeName != 'BUTTON') {
clickedElement = clickedElement.parentElement;
}
var dropdownElement = clickedElement.nextElementSibling;
dropdownElement.classList.add('tempClass'); //adding tempclass to avoid this in below loop
var allOtherDropdowns = document.getElementsByClassName('dropdown-content');
//close all other dropdowns
for (var i = 0; i < allOtherDropdowns.length; i++) {
if (!allOtherDropdowns[i].classList.contains('tempClass')) {
allOtherDropdowns[i].classList.remove('show');
}
}
dropdownElement.classList.toggle("show");
dropdownElement.classList.remove('tempClass'); //removing the temp class here
}
// Close the dropdown if the user clicks outside of it
window.onclick = function(e) {
if (!e.target.matches('.dropbtn')) {
var allDropdowns = document.getElementsByClassName('dropdown-content');
//close all other dropdowns
for (var i = 0; i < allDropdowns.length; i++) {
allDropdowns[i].classList.remove('show');
}
}
}
i{
width: 0;
height: 0;
border-style: solid;
border-width: 8px 5px 0 5px;
border-color: #ffffff transparent transparent transparent;
}
.icon{
position: relative;
/* Adjust these values accordingly */
top: 14px;
left: 9px;
}
nav {
height: 40px
overflow: hidden;
background-color: #333;
font-family: Arial, Helvetica, sans-serif;
}
nav a {
float: left;
font-size: 16px;
color: white;
text-align: center;
padding: 14px 16px;
text-decoration: none;
}
.dropdown {
float: left;
overflow: hidden;
}
.drop-btn{
float: right;
}
.dropdown .dropbtn {
cursor: pointer;
font-size: 14px;
border: none;
outline: none;
color: white;
padding: 10px 10px;
background-color: inherit;
font-family: inherit;
margin: 0;
}
nav 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">
</head>
<body>
<nav>
<div class="dropdown">
<button class="dropbtn" onclick="myFunction(event)">Programming
<i class="icon"></i>
</button>
<div class="dropdown-content">
Java
C++
Python
Swift
</div>
</div>
<div class="dropdown">
<button class="dropbtn" onclick="myFunction(event)">Platform
<i class="icon"></i>
</button>
<div class="dropdown-content">
Linux
Windows
Development Editor
</div>
</div>
<div class="dropdown">
<button class="dropbtn" >Algorithm
</button>
</div>
<div class="dropdown">
<button class="dropbtn" onclick="myFunction(event)">Upgrade 4
<i class="icon"></i>
</button>
<div class="dropdown-content">
item 10
item 11
item 12
</div>
</div>
<div class="dropdown">
<button class="dropbtn" onclick="myFunction(event)">Upgrade 4
<i class="icon"></i>
</button>
<div class="dropdown-content">
item 10
item 11
item 12
</div>
</div>
<div class="dropdown">
<button class="dropbtn" onclick="myFunction(event)">Upgrade 4
<i class="icon"></i>
</button>
<div class="dropdown-content">
item 10
item 11
item 12
</div>
</div>
<nav>
<h3>Dropdown Menu inside a Navigation Bar</h3>
<p>Click on the "Dropdown" link to see the dropdown menu.</p>
</body>
</html>
Your h3 with the text Dropdown Menu inside a Navigation Bar had a margin. Also your body had a small margin. Should be fine now.
function myFunction(event) {
var clickedElement = event.target;
//console.log(clickedElement);
if (clickedElement.nodeName != 'BUTTON') {
clickedElement = clickedElement.parentElement;
}
var dropdownElement = clickedElement.nextElementSibling;
dropdownElement.classList.add('tempClass'); //adding tempclass to avoid this in below loop
var allOtherDropdowns = document.getElementsByClassName('dropdown-content');
//close all other dropdowns
for (var i = 0; i < allOtherDropdowns.length; i++) {
if (!allOtherDropdowns[i].classList.contains('tempClass')) {
allOtherDropdowns[i].classList.remove('show');
}
}
dropdownElement.classList.toggle("show");
dropdownElement.classList.remove('tempClass'); //removing the temp class here
}
// Close the dropdown if the user clicks outside of it
window.onclick = function(e) {
if (!e.target.matches('.dropbtn')) {
var allDropdowns = document.getElementsByClassName('dropdown-content');
//close all other dropdowns
for (var i = 0; i < allDropdowns.length; i++) {
allDropdowns[i].classList.remove('show');
}
}
}
function myFunc(){return true}
h3,body,html{
margin:0;
padding:0;
}
i {
width: 0;
height: 0;
border-style: solid;
border-width: 8px 5px 0 5px;
border-color: #ffffff transparent transparent transparent;
}
.icon {
position: relative;
/* Adjust these values accordingly */
top: 14px;
left: 9px;
}
nav {
height: 40px overflow: hidden;
background-color: #333;
font-family: Arial, Helvetica, sans-serif;
}
nav a {
float: left;
font-size: 16px;
color: white;
text-align: center;
padding: 14px 16px;
text-decoration: none;
}
.dropdown {
float: left;
overflow: hidden;
}
.drop-btn {
float: right;
}
.dropdown .dropbtn {
cursor: pointer;
font-size: 14px;
border: none;
outline: none;
color: white;
padding: 10px 10px;
background-color: inherit;
font-family: inherit;
margin: 0;
}
nav 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">
</head>
<body>
<nav>
<div class="dropdown">
<button class="dropbtn" onclick="myFunction(event)">Programming
<i class="icon"></i>
</button>
<div class="dropdown-content">
Java
C++
Python
Swift
</div>
</div>
<div class="dropdown">
<button class="dropbtn" onclick="myFunction(event)">Platform
<i class="icon"></i>
</button>
<div class="dropdown-content">
Linux
Windows
Development Editor
</div>
</div>
<div class="dropdown">
<button class="dropbtn">Algorithm
</button>
</div>
<div class="dropdown">
<button class="dropbtn" onclick="myFunction(event)">Upgrade 4
<i class="icon"></i>
</button>
<div class="dropdown-content">
item 10
item 11
item 12
</div>
</div>
<div class="dropdown">
<button class="dropbtn" onclick="myFunction(event)">Upgrade 4
<i class="icon"></i>
</button>
<div class="dropdown-content">
item 10
item 11
item 12
</div>
</div>
<div class="dropdown">
<button class="dropbtn" onclick="myFunction(event)">Upgrade 4
<i class="icon"></i>
</button>
<div class="dropdown-content">
item 10
item 11
item 12
</div>
</div>
<nav>
<h3>Dropdown Menu inside a Navigation Bar</h3>
<p>Click on the "Dropdown" link to see the dropdown menu.</p>
</body>
</html>

Drop-down menu in navbar with Javascript not working

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">
Link 1
Link 2
Link 3
</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">
Link 1
Link 2
Link 3
</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">
Link 1
Link 2
Link 3
</div>
</div>
</div>
</body>
</html>
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 ids in the first place, while it seems like an easy approach, causes brittle code that doesn't scale (as you've found), so avoid ids 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">
Home 1
About 1
Contact 1
</div>
</div>
<div class="dropdown">
<button class="dropbtn">Dropdown 2</button>
<div class="dropdown-content">
Home 2
About 2
Contact 2
</div>
</div>
<div class="dropdown">
<button class="dropbtn">Dropdown 3</button>
<div class="dropdown-content">
Home 3
About 3
Contact 3
</div>
</div>
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">
Home 1
About 1
Contact 1
</div>
</div>
<div class="dropdown">
<button onclick="myFunction(this)" data-target="dropdown2" class="dropbtn">Dropdown 2</button>
<div id="dropdown2" class="dropdown-content">
Home 2
About 2
Contact 2
</div>
</div>
<div class="dropdown">
<button onclick="myFunction(this)" data-target="dropdown3" class="dropbtn">Dropdown 3</button>
<div id="dropdown3" class="dropdown-content">
Home 3
About 3
Contact 3
</div>
</div>
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">
Home 1
About 1
Contact 1
</div>
</div>
<div class="dropdown">
<button class="dropbtn">Dropdown 2</button>
<div class="dropdown-content">
Home 2
About 2
Contact 2
</div>
</div>
<div class="dropdown">
<button class="dropbtn">Dropdown 3</button>
<div class="dropdown-content">
Home 3
About 3
Contact 3
</div>
</div>

Open accordion on load with active class

I have an accordion on my website and I would like for the accordion to be open at the right level depending on where the active class is. I have made a JSFiddle.
JS:
$(document).ready(function ($) {
$('.servicesub').find('.servicesubitem').click(function () {
if ($(this).next().is(':visible')) {
//Collapse
$(this).next().slideToggle('fast');
$(this).removeClass('active');
// $("#footer-wrapper").animate({marginTop: "0px"}, 'fast');
} else {
//Expand
$(this).next().slideToggle('fast');
$(this).siblings().removeClass('active');
$(this).addClass('active');
//hide other panels
$(".servicesubli").not($(this).next()).slideUp('fast');
//$("#footer-wrapper").animate({marginTop: "200px"}, 'fast');
}
});
});
HTML:
<div class="col-xs-12 col-md-3 col-lg-3 servicesub" id="servicesub" >
<li class="servicesubitem active">
<span class="subitem">Web Design,
<br>
Multimedia & Email</span><span class="fa1 fa-globe"> </span>
</li>
<div class="servicesubli">
<ul>
<a href="domains.php">
<li>
Domain Registration
</li>
</a>
<a href="webdesign.php">
<li>
Web Design & Development
</li>
</a>
<a href="webhosting.php">
<li>
Web Hosting
</li>
</a>
<a href="email.php">
<li>
Managed Email Systems
</li>
</a>
</ul>
</div>
<li class="servicesubitem">
<span class="subitem">Vessel
<br>
Security</span><span class="fa1 fa-lock"> </span>
</li>
<div class="servicesubli">
<ul>
<a href="tracking.php">
<li>
Yacht Tracking
</li>
</a>
<a href="ssas.php">
<li>
SSAS
</li>
</a>
<a href="#">
<li>
SAT C
</li>
</a>
</ul>
</div>
</div>
CSS:
* Service Sub */
.servicesub { padding:10px; }
.servicesub ul { list-style-type: none; padding: 0px; color: #fff;}
.servicesub li{ font-size: 14px; height: 70px; padding: 17px 0px 10px 20px; margin-top: 10px; text-transform: uppercase; }
.servicesub li a {text-decoration: none;}
.servicesub li a:hover {color:#fff;}
.servicesub li { background-color: #017CEB; }
.servicesub li:hover { background-color: #015BAC; }
.servicesub li.active { background-color: #015BAC; }
.servicesub span:after { color:#fff; font-family: FontAwesome; display: inline-block; width: 1.2em; font-size: 40px; position: absolute; text-align: center; margin-top: -9px; }
#servicesub.stick { position: fixed; top: 80px; max-width: 293px; }
.subitem { color:#fff; height:58px; width: 215px; position: absolute; right: 10px; text-align: center; }
.servicesubitem { cursor: pointer; }
.servicesubli { cursor: pointer; display: none; }
.servicesubli.default { display: block; }
.servicesubli ul { width: 100%; font-size: 14px;}
.servicesubli li { padding: 8px; margin-top: 1px; text-transform: uppercase; height: 35px; text-align: center;}
.servicesubli a { text-decoration: none; color: #fff; }
.servicesub .getintouch { background-color: #00539f; padding: 10px; height: auto;}
.servicesub .getintouch:hover { background-color: #00539f; }
.servicesub .getintouch h3 { color: #fff; text-align: center; }
.servicesub .getintouch p { color:#fff; text-align: center; }
As you can see the accordion works to click on and the active class (which is set manually for this demo) is there I just want it so that the correct accordion part is toggled when the page is loaded. Thanks in advance.
To recycle your logic, You can just add your .active class to whichever element you wish, then search for .servicesubli.active on ready. Observe the following...
<div class="servicesubli active">
$(function() {
[...]
$('.servicesubli.active').slideToggle('fast');
});
JSFiddle Link - demo
Per comments, if you wish to target off servicesubitem.active, just modify to the following...
$('.servicesubitem.active').next('.servicesubli').addClass('active').slideToggle('fast');
JSFiddle Link - demo - .servicesubitem.active selector
Well you just need to trigger the click event once the page is loaded like below:
$('.servicesub').find('.active').trigger( "click" );
See the jsfiddle here: http://jsfiddle.net/beroza/a1mbgyqx/

Categories

Resources