Responsive navbar with dropdown mobile hamburger icon disappears when toggled - javascript

The drop-down menu works fine on the laptop.
On the mobile device it comes up as a single bar. When I select the hamburger icon, the drop-down are displays as they should. When I select one of the buttons, the link works. But if I instead hit the hamburger icon the second time, the hamburger and complete bar disappear. The only way to bring the navbar back is to do a browser refresh.
I have tried several responsive navbar code selections and this is the closest to a working responsive navbar.
HTML code
...
<nav>
<div class="topnav" id="myTopnav">
Home
New Here
<div class="dropdown">
<button class="dropbtn">Ministries
<i class="fa fa-caret-down"></i>
</button>
<div class="dropdown-content">
Adult
Member Care
Outreach
Youth
</div>
</div>
Donate
...
Contact
About
☰
</div>
</nav>
CSS code
...
/* When the screen is less than 600 pixels wide, hide all links, except for the first one ("Home"). Show the link that contains should open and close the topnav (.icon) */
#media screen and (max-width: 600px) {
.topnav a:not(:first-child), .dropdown .dropbtn {
display: none;
}
.topnav a.icon {
float: right;
display: block;
}
}
/* The "responsive" class is added to the topnav with JavaScript when the user clicks on the icon. This class makes the topnav look good on small screens (display the links vertically instead of horizontally) */
#media screen and (max-width: 600px) {
.topnav.responsive {position: relative;}
.topnav.responsive a.icon {
position: absolute;
right: 0;
top: 0;
}
.topnav.responsive a {
float: none;
display: block;
text-align: left;
}
.topnav.responsive .dropdown {float: none;}
.topnav.responsive .dropdown-content {position: relative;}
.topnav.responsive .dropdown .dropbtn {
display: block;
width: 100%;
text-align: left;
}
}
...
javascript code
/* Toggle between showing and hiding the navigation menu links when the user clicks on the hamburger menu / bar icon */
function navBarIcon() {
var x = document.getElementById("myTopnav");
if (x.className === "topnav") {
x.className += " responsive";
} else {
x.className = "topnav";
}
if (x.style.display === "block") {
x.style.display = "none";
} else {
x.style.display = "block";
}
}
//* Loop through all dropdown buttons to toggle between hiding and showing its dropdown content - This allows the user to have multiple dropdowns without any conflict */
var dropdown = document.getElementsByClassName("dropdown-btn");
var i;
for (i = 0; i < dropdown.length; i++) {
dropdown[i].addEventListener("click", function() {
this.classList.toggle("active");
var dropdownContent = this.nextElementSibling;
if (dropdownContent.style.display === "block") {
dropdownContent.style.display = "none";
} else {
dropdownContent.style.display = "block";
}
});
}
As I mentioned, the code works except when the hamburger icon is hit a second time to close the navbar. It goes beyond closing, but rather disappears.

Modified javascript and it works now.
/* Toggle between showing and hiding the navigation menu links when the user clicks on the hamburger menu / bar icon */
function navBarIcon() {
var x = document.getElementById("myTopnav");
if (x.className === "topnav") {
x.className += " responsive";
} else {
x.className = "topnav";
}
}
//* Loop through all dropdown buttons to toggle between hiding and showing its dropdown content - This allows the user to have multiple dropdowns without any conflict */
var dropdown = document.getElementsByClassName("dropdown-btn");
var i;
for (i = 0; i < dropdown.length; i++) {
dropdown[i].addEventListener("click", function() {
this.classList.toggle("active");
var dropdownContent = this.nextElementSibling;
if (dropdownContent.style.display === "block") {
dropdownContent.style.display = "none";
} else {
dropdownContent.style.display = "block";
}
});
}

Related

How to hide navigation bar on link click?

I have 3 buttons and a responsive hamburger menu. Everything works as expected, but I can't think of a way to make a navigation bar go away as soon as I click on a button.
The program is supposed to work like this: clicking hamburger menu activates 3 buttons, whenever user clicks on any of those 3 buttons it hides the buttons and only leaves the button that was clicked.
This is the wanted outcome:
This is my code so far.
html:
<div class="selectSection">
<button type="button" data-number="1" class="active">1</button>
<button type="button" data-number="2">2</button>
<button type="button" data-number="3">3</button>
</div>
<div class="hamburger">
<div class="line"></div>
<div class="line"></div>
<div class="line"></div>
</div>
<div>
<div class="content" data-number="1">
<p>1st page</p>
</div>
<div class="content" data-number="2">
<p>2nd page</p>
</div>
<div class="content" data-number="3">
<p>3rd page</p>
</div>
</div>
css
.content:not(:first-child) {
display: none;
}
.active {
color: orange !important;
}
.hamburger {
display: none;
}
#media all and (max-width: 800px) {
.hamburger {
display: inline-block;
cursor: pointer;
z-index: 7;
}
.hamburger .line {
width: 30px;
height: 3px;
background: black;
margin: 6px 0px;
}
.selectSection {
display: none;
overflow: hidden;
}
.selectSection.active {
display: block;
}
}
js
// change active class, show the clicked element only and hide the others
// grab all the buttons
let Buttons = document.querySelectorAll(".selectSection button");
// loop through the buttons using for..of
for (let button of Buttons) {
// listen for a click event
button.addEventListener("click", (e) => {
// et = event target
const et = e.target;
// slect active class
const active = document.querySelector(".active");
// check for the button that has active class and remove it
if (active) {
active.classList.remove("active");
}
// add active class to the clicked element
et.classList.add("active");
// select all classes with the name content
let allContent = document.querySelectorAll(".content");
// loop through all content classes
for (let content of allContent) {
// display the content if the class has the same data-attribute as the button
if (
content.getAttribute("data-number") ===
button.getAttribute("data-number")
) {
content.style.display = "block";
}
// if it's not equal then hide it.
else {
content.style.display = "none";
}
}
});
}
hamburger = document.querySelector(".hamburger");
hamburger.onclick = function () {
navBar = document.querySelector(".selectSection");
navBar.classList.toggle("activate");
};
This is the demo:
https://codepen.io/f4kermak3r/pen/ExRPKzJ
you are using the wrong css class in your js file. At line 44, you must change navBar.classList.toggle("activate") to navBar.classList.toggle("active"). That should work.

Accordion scroll to top when clicked?

I have these accordions that open and close. I'd also like the accordion to scroll to the top of the page when it's clicked.
HTML:
<button class="accordion"><h2>Title</h></button>
<div class="panel">
<p>some text</p>
</div>
Javascript that works to open and close the accordion:
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
/* Toggle between adding and removing the "active" class,
to highlight the button that controls the panel */
this.classList.toggle("active");
/* Toggle between hiding and showing the active panel */
var panel = this.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
});
}
Javascript I tried to add to make it scroll to the top but it doesn't work:
$('button').click(function() {
$(this).animate({
scrollTop:0
}, 1000);
});
So, I think you can change your approach.
Considering you're using jQuery, your HTML can be like this:
...
<div class="accordion">
<div class="accordion-header">Your accordion header</div>
<div class="accordion-content">Your Accordion Content</div>
</div>
...
your Javascript like this:
function scrollToElement($el, time = 500){
$([document.documentElement, document.body]).animate({
scrollTop: $el.offset().top
}, time);
}
function setupAccordion(){
$('.accordion .accordion-header').click(function(){
let $parent = $(this).parent();
$parent.toggleClass('active');
scrollToElement($parent);
});
}
$(document).ready(function(){
setupAccordion();
});
And your CSS like this:
.accordion-header{
border-bottom:1px solid #ccc;
padding:1em;
cursor:pointer;
font-weight:bold;
}
.accordion-content{
max-height:0;
opacity:0;
visibility:hidden;
transition:all 0.2s ease;
padding:0;
}
.accordion.active .accordion-content{
max-height:500px;
visibility:visible;
opacity:1;
padding:1em;
}
Playground: https://jsfiddle.net/m0fbq2j4/

Having trouble hiding menu when resizing and when button is pressed

I'm using this code:
#media screen and (max-width: 850px) {
#side-menu {
display: none;
}
button {
display: block;
}
}
to hide my side menu and display a button when I resize window. I also want to show and hide menu when the button is pressed. To do that I'm using this code:
function showMenu() {
var sideMenu = document.getElementById("side-menu");
if (sideMenu.style.display === "none") {
sideMenu.style.display = "block";
}
else {
sideMenu.style.display = "none";
}
}
When I hide with button the menu does not reappear when I resize window. I believe this is happening because the javaScript changes the primary style to display: none, so once it's out of range it applies the primary style. Now it's display: none so it doesn't appear again. How can I get it to work how I intend it to? Also, it takes two clicks to show menu for some reason.
<ul id="side-menu">
<li>example1</li>
<li>example2</li>
<li>example3</li>
<li>example4</li>
</ul>
html just in case you need it.
You must check if the display === "block" first to fix the multiple click issue.
Included media query to manage window width that is greater than 850px to show list and hide button.
EDIT: updated snippet to use the list provided in the original question.
function showMenu() {
var sideMenu = document.getElementById("side-menu");
if (sideMenu.style.display === "block") {
sideMenu.style.display = "none";
}
else {
sideMenu.style.display = "block";
}
}
#media screen and (min-width: 850px) {
#side-menu {
display: block;
}
button {
display: none;
}
}
#media screen and (max-width: 850px) {
#side-menu {
display: none;
}
button {
display: block;
}
}
<div id="side-menu">
<ul>
<li>example1</li>
<li>example2</li>
<li>example3</li>
<li>example4</li>
</ul>
</div>
<button onclick="showMenu()">click me</button>
//swap none with block to fix double button press
function showMenu() {
var sideMenu = document.getElementById("side-menu");
if (sideMenu.style.display === "block") {
sideMenu.style.display = "none";
}
else {
sideMenu.style.display = "block";
}
}
/* add this to fix menu show*/
#media screen and (min-width: 850px) {
#side-menu {
display: block !important;
}
button {
display: none;
}
}
#media screen and (max-width: 850px) {
#side-menu {
display: none;
}
button {
display: block;
}
}
<div id="side-menu">
<ul>
<li>example1</li>
<li>example2</li>
<li>example3</li>
<li>example4</li>
</ul>
</div>
<button onclick="showMenu()">click me</button>
Thanks ksa and StackSlave

Add display property to accordion onload depending on resolution

I'm using the W3C accordion on my website, and only want the accordion to be active when the page is under 768px. So far, I have the script adjusted so that the "panel" div's will toggle, but they initially are displayed, rather than hidden. Is there a line I can add to the code to initially hide the panel div's when the resolution is under 768px? I've tried adding display:none to the element in the css sheet, but the toggle script won't override it.
Hope this makes sense!
<script>
if (screen.width < 768) {
var acc = document.getElementsByClassName("filterAccordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
});
}
}
</script>
I have a feeling you can manage this in CSS..
#media only screen and (max-width: 768px) {
.filterAccordion {
display: none;
}
}
As for the accordian and mentioned by Quentin.. W3Schools is probably not the best source of information.. For general modules like this perhaps Bootstrap(3/4) might be a more ideal framework if you are open to use one at all.
Edit : MediaQueries
Here's a working solution. Please note that I have commented out some code to demonstrate it in desktop view. Please uncomment that and your code should work in "mobile only" scenario.
document.querySelector('.accordion').addEventListener('click', function (e) {
/*if (screen.width < 768) {*/
var currentTarget = e.target;
if (e.target.classList.contains('accordion-title')) {
var allDesc = Array.prototype.slice.call(document.querySelectorAll('.accordion-description'));
allDesc.forEach(function (el) {
el.classList.add('hidden-xs');
});
e.target.nextElementSibling.classList.remove('hidden-xs');
}
/*}*/
});
/*#media only screen and (max-width: 767px) {
.hidden-xs {
display: none;
}
}*/
/* Comment below code and uncomment above */
/* For demo purpose only */
.hidden-xs {
display: none;
}
.accordion-title,
.accordion-description {
padding: 20px;
margin-bottom: 10px;
}
.accordion-title {
background-color: #ccc;
border-radius: 3px;
border: 1px solid;
}
<div class="accordion">
<div class="accordion-title">Title 1</div>
<div class="accordion-description hidden-xs">Some description</div>
<div class="accordion-title">Title 2</div>
<div class="accordion-description hidden-xs">Some description</div>
</div>

Javascript: Avoiding multiple pop up boxes / check if div is empty

I created a pop up box that appears when a user clicks a button. Currently I am able to get the box to appear but when the user closes it and re-opens it the code is ran through again and another box is stacked on top of the old one.
What I want to do is make it so no matter how many times the user clicks the box it only shows one box... my thoughts was maybe checking if it was empty similar to How do I check if an HTML element is empty using jQuery? however that has not worked so far.
Any suggestions for a noob idiot? Appreciation for all responses in advance.
<button onclick="popup()">text</button>
<script>
var box = document.getElementById('popupbox');
function popup(){
box.style.display = "block";
var content = document.createElement('div');
content.className = 'boxstyle';
content.innerHTML = ' ...a handful of tags...';
box.appendChild(content);}
function exit(){
box.style.display = "none";}
</script>
You can create a popup using a modal as follows. I just copied code from here
<!DOCTYPE html>
<html>
<head>
<style>
/* The Modal (background) */
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 1; /* Sit on top */
padding-top: 100px; /* Location of the box */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}
/* Modal Content */
.modal-content {
background-color: #fefefe;
margin: auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
}
/* The Close Button */
.close {
color: #aaaaaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
</style>
</head>
<body>
<h2>Modal Example</h2>
<!-- Trigger/Open The Modal -->
<button id="myBtn">Open Modal</button>
<!-- The Modal -->
<div id="myModal" class="modal">
<!-- Modal content -->
<div class="modal-content">
<span class="close">×</span>
<p>Some text in the Modal..</p>
</div>
</div>
<script>
// Get the modal
var modal = document.getElementById('myModal');
// Get the button that opens the modal
var btn = document.getElementById("myBtn");
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];
// When the user clicks the button, open the modal
btn.onclick = function() {
modal.style.display = "block";
}
// When the user clicks on <span> (x), close the modal
span.onclick = function() {
modal.style.display = "none";
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
</script>
</body>
</html>
I actually managed to solve it by simply tossing in box.innerHTML = '' right after the block appears so that it has a clean slate to work with. I was trying to go a little more elegant and seeking to use an If/Else statement but in the end it seems to work. Much appreciation for all who answered / commented, you all are awesome!
<button onclick="popup()">text</button>
<script>
var box = document.getElementById('popupbox');
function popup(){
box.style.display = "block";
box.innerHTML = '';
var content = document.createElement('div');
content.className = 'boxstyle';
content.innerHTML = ' ...a handful of tags...';
box.appendChild(content);}
function exit(){
box.style.display = "none";}

Categories