Having trouble closing the Menu after clicking the hamburger button. What's the best way to close the entire menu screen once any of the items are clicked?
My HTML is:
`<body>
<div class="menu-wrap">
<input type="checkbox" class="toggler">
<div class="hamburger">
<div></div>
</div>
<div class="menu">>
<div>
<div>
<ul>
<li>Home</li>
<li>About</li>
<li>Menu</li>
<li>Contact</li>
</ul>
</div>
</div>
</div>
</div>`
I've tried using jQuery but havent had success. Here's the js code:
`$('.toggler').on('click', function () {
$('.menu').toggleClass('open');
});
$('.menu li').on("click", function () {
$('.menu-wrap').toggleClass('open');
});`
Or if there's a simpler way using CSS to close the menu?
Here's the codepen to run: https://jsfiddle.net/7rmcx861/#&togetherjs=g5zDdkhjc5
https://jsfiddle.net/h7et0qnv/
this menu style work on input chechbox situation. If checked your hamburger menu get visible else get hidden . so just need to change its situation
wrote one function in your script.
function toggle(){
$(".toggler").prop("checked", false);
}
then put this function to onclick event of menu list
<li><a onclick="toggle()" href="#Home">Home</a></li>
<li><a onclick="toggle()" href="#About">About</a></li>
<li><a onclick="toggle()" href="#">Menu</a></li>
<li><a onclick="toggle()" href="#">Contact</a></li>
If you want to do it with vanilla js, I would suggest you to use CustomEvents. There might be other ways of doing it in frameworks like React.
For every menu item I would emit a custom event -
var menuItems = document.querySelectorAll('.menu li');
for (var i = 0; i < menuItems.length; ++i) {
menuItems[i].addEventListener('click', function(e) {
var closeEvent = new CustomEvent('closeMenu', {
bubbles: true,
});
e.currentTarget.dispatchEvent(closeEvent);
});
}
The 'menu' can then react to this custom event and close itself if open -
var menu = document.querySelector('.menu')
if (menu) {
menu.addEventListener('closeMenu', function (e) {
e.currentTarget.classList.remove('open');
});
}
You can have the usual menu 'toggler' for opening and closing the menu when it is clicked.
Update:
I figured things were not very clear. So here I am adding some sample code.
Note: I added the toggler and subsequently changed the menu eventHandler slightly.
var menuItems = document.querySelectorAll('.menu li');
for (var i = 0; i < menuItems.length; ++i) {
menuItems[i].addEventListener('click', function(e) {
var closeEvent = new CustomEvent('closeMenu', {
bubbles: true,
});
e.currentTarget.dispatchEvent(closeEvent);
});
}
var menu = document.querySelector('.menu')
var toggler = document.querySelector('.toggler')
if (menu && toggler) {
menu.addEventListener('closeMenu', function(e) {
menu.classList.remove('open');
toggler.checked = false;
});
toggler.addEventListener('click', function(e) {
menu.classList.toggle('open');
});
}
.menu {
background-color: white;
display: inline-block;
padding-right: 1rem;
}
.menu.open {
visibility: visible;
}
.menu {
visibility: hidden;
}
<div class="menu-wrap">
<input type="checkbox" class="toggler" checked>
<div class="hamburger">
<div></div>
</div>
<div class="menu open">
<div>
<div>
<ul>
<li>Home</li>
<li>About</li>
<li>Menu</li>
<li>Contact</li>
</ul>
</div>
</div>
</div>
</div>
Related
hope you all doing great.
I've been trying to add the (active class )to each of the navbar links when the user is on that specific section of the page with this
Tutorial (i'm stuck at 2:45:05) and no success so far can anyone tell me what i did wrong .thank you.
const menu = document.querySelector(' nav .container ul');
const navItems = menu.querySelectorAll('li');
navItems.forEach(item => {
const link = item.querySelector('a');
ink.addEventListener('click', () => {
link.classList.add(".active");
});
});
nav .container ul li a.active {
background: var(--color-primary);
color: var(--color-white);
}
<nav>
<div class="container">
<a href="#">
<h3> AMANI DEV </h3>
</a>
<ul>
<li>Home</li>
<li>About</li>
<li>Skills</li>
<li>Services </li>
<li>Portfolio </li>
<li>Contact Me </li>
</ul>
</div>
</nav>
Typo with ink not link.
When you assign a class with classList you don't include the .: classList.add('active').
In your CSS background should probably be background-color.
If you want to remove the other active links before applying the new one you can use forEach to iterate over the links and use classList.remove('active') on each one.
You may find event delegation easier to manage. Rather than attaching multiple listeners to multiple elements attach one listener to the list element that watches out for events from its child elements as they "bubble up the DOM. You can then check that the clicked element is a link, remove the active classes from the previous link(s), and then apply the active class to the clicked link.
Here's an example using event delegation.
// Cache the list, and the items
const list = document.querySelector(' nav .container ul');
const links = list.querySelectorAll('a');
// Add one listener to the list element
list.addEventListener('click', handleClick);
// If the clicked element is a link remove all
// the active classes from the other links, and then
// add the active class to the link that was clicked on
function handleClick(e) {
if (e.target.matches('a')) {
links.forEach(link => link.classList.remove('active'));
e.target.classList.add('active');
}
}
:root { --color-white: white; --color-primary: red; }
.active {
background-color: var(--color-primary);
color: var(--color-white);
}
<nav>
<div class="container">
<a href="#">
<h3> AMANI DEV </h3>
</a>
<ul>
<li><a class="active" href="#home">Home</a></li>
<li>About</li>
<li>Skills</li>
<li>Services </li>
<li>Portfolio </li>
<li>Contact Me </li>
</ul>
</div>
</nav>
You need to do querySelectorAll in a tag not on the li tag. Just do this and do let me know.
Modify the code in the following line :
ink.addEventListener('click',() => {
to
link.addEventListener('click',() => {
to be like this
const menu = document.querySelector(' nav .container ul');
const navItems = menu.querySelectorAll('li');
navItems.forEach(item => {
const link = item.querySelector('a');
link.addEventListener('click',() => {
link.classList.add(".active");
});
});
document.querySelectorAll('ul li').forEach(el => {
el.onclick = () => {
document.querySelectorAll('ul li').forEach(el => el.classList.remove('active'));
el.classList.add('active');
}
})
here a demo code:
document.querySelectorAll('#myNav li').forEach(el => {
el.onclick = () => {
document.querySelectorAll('#myNav li').forEach(el => el.classList.remove('active'));
el.classList.add('active');
}
})
.active {
font-size: 70px;
}
<nav>
<div class="container">
<a href="#">
<h3> AMANI DEV </h3>
</a>
<ul id="myNav">
<li><a class="active" href="#home">Home</a></li>
<li>About</li>
<li>Skills</li>
<li>Services </li>
<li>Portfolio </li>
<li>Contact Me </li>
</ul>
</div>
</nav>
// selecting all a element on the page
const links = document.querySelectorAll('a');
// adding a click event on all elements
links.forEach((link) => {
link.addEventListener('click', (e) => {
// if we click first thing is deleting the active class from all link
links.forEach((link) => {
link.classList.remove('active')
})
// then in the end add the active class only in the correct one
e.target.classList.add('active')
})
})
What am I trying to do. I have a menu navigation with 2 menu items the search and hamburger icon next to each other.
When I click on "MENU" the div will display the menu navigation items and will close when I click once again because of the toggle event.
However, when I open up "MENU" and switch back to "SEARCH" where, a different div should be displayed it messes up the logical structure between these two on toggle.
So, I want to toggle between SEARCH and MENU content no matter which one is selected / toggled. To close previous (remove class and add class to the next active element).
How can I do this?
HTML:
SEARCH
MENU
<nav class="navigation js-navigation">
<div class="content hidden">
<input type="search" placeholder="search" />
</div>
<div class="content hidden">
<ul>
<li>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
</div>
</nav>
JS:
(() => {
const navigation = document.querySelector('.js-navigation');
if(!navigation) {
return;
}
const hamburger = document.querySelector('.js-hamburger');
const search = document.querySelector('.js-search');
let contents = document.querySelectorAll('.content');
const onClick = (e) => {
e.preventDefault();
contents.forEach((content) => {
content.classList.remove('hidden');
content.classList.add('hidden');
})
}
hamburger.addEventListener('click', onClick);
search.addEventListener('click', onClick);
});
Shouldnt you add:
if (content.classList.contains("hidden")) {
content.classList.remove('hidden');
} else {
content.classList.add('hidden');
}
Changeing classList didnt work for me, but this took effect:
<html>
<body>
SEARCH
MENU
<nav class="navigation js-navigation">
<div id="search" class="content">
<input type="search" placeholder="search" />
</div>
<div id="menu" class="content">
<ul>
<li>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
</div>
</nav>
<script>
function toggle(id) {
var isHidden = document.getElementById(id).style.visibility == "hidden";
document.getElementById(id).style.visibility = isHidden ? "visible" : "hidden";
}
</script>
</body>
</html>
Also seems you could alternatively go with classList.toggle:
const navigation = document.querySelector('.js-navigation');
const hamburger = document.querySelector('.js-hamburger');
const search = document.querySelector('.js-search');
let contents = document.querySelectorAll('.content');
const onClick = (e) => {
e.preventDefault();
contents.forEach((content) => {
content.classList.toggle('hidden');
})
}
hamburger.addEventListener('click', onClick);
search.addEventListener('click', onClick);
I am making a dropdown menu in a dropdown, I want that I have a few head items and if you click on one, the dropdown in that head item is displayed as a block element. But the problem is that they all have the same class and when I want to add a class all the dropdowns inside the head items get that class. What am I doing wrong here?
jQuery(document).ready(function(){
var click = false;
jQuery(".navbar-collapse .nav li").click(function() {
if(click == false) {
jQuery(".navbar-collapse .nav li ul").addClass('clicked');
click = true;
} else {
jQuery(".navbar-collapse .nav li ul").removeClass('clicked');
click = false;
}
});
});
.clicked {
display: block !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="nav menu">
<li class="item-101 default deeper parent">
Home
<ul class="nav-child unstyled small clicked">
<li class="item-124">
Maandmail
</li>
</ul>
</li>
<li class="item-102 default deeper parent">
Contact
<ul class="nav-child unstyled small clicked">
<li class="item-125">
Contact pagina
</li>
</ul>
</li>
</ul>
Does anyone know why this is happening and how to fix this issue?
You have to make the code look at the specific UL relative to the item you've clicked on:
jQuery(document).ready(function() {
var click = false;
jQuery(".navbar-collapse .nav li").click(function(e) {
if (click == false) {
jQuery(e.currentTarget).find("ul").addClass('clicked');
click = true;
} else {
jQuery(e.currentTarget).find("ul").removeClass('clicked');
click = false;
}
});
});
I have a problem with my JS code, this code active a div with megamenu but i can open 2 megamenu at the same time, i need when i have already clicked the current megamenu disappears for the second is active. You have an idea ?
$(function() {
var menuVisible = false;
$('.contentLink').click(function() {
var office = $(this).attr('data-office');
if (menuVisible) {
$('#_' + office).hide();
$(this).removeClass('on');
menuVisible = false;
return;
}
else
{
$('#_' + office).show();
$(this).addClass('on');
menuVisible = true;
}
});
});
<nav>
<ul class="menu-links">
<li><a data-office="events" class="contentLink">Events</a>
<div class="megamenu center" id="_events">
My mega menu events
</div>
</li>
<li><a data-office="articles" class="contentLink">Articles</a>
<div class="megamenu center" id="_articles">
My mega menu articles
</div>
</li>
</ul>
</nav>
Yes, add this line on your click() function to hide all megamenu before :
$('.megamenu').hide();
I've edit your code to simplify it :
$(function() {
$('.contentLink').click(function() {
$('.megamenu').hide();
menu = $(this).next();
if(menu.is(':visible')){
menu.hide();
}else{
menu.show();
}
});
});
Live example
I making a single page website. When I open my menu and click on a li item, I want my menu to close.
For the moment it is working when I click back on the "menu-burger-wrapper" and I want to set the same thing when I click on items li.
There is my code:
$(document).ready(function() {
$('#menu-burger-wrapper').click(function(e) {
e.preventDefault();
$this = $(this);
if ($this.hasClass('is-opened')) {
$this.addClass('is-closed').removeClass('is-opened');
} else {
$this.removeClass('is-closed').addClass('is-opened');
}
})
});
<nav class="menu-base" id="menu-base">
<ul class="menu-item">
<a id="en-cours" class="work_menu link link--over">
<li>works</li>
</a>
<a class="about_menu link link--over">
<li>about</li>
</a>
<a class="link link--over">
<li>contact</li>
</a>
</ul>
</nav>
<!-- Header -->
<div id="header">
<!-- Menu -->
<div id="menu-burger-wrapper">
<div id="menu-burger">
<div class="line line-1"></div>
<div class="line line-2"></div>
<div class="line line-3"></div>
</div>
</div>
Try this - just attach the click handler to the li elements.
var clickHandler = function (e) {
e.preventDefault();
$this = $(this);
if ($this.hasClass('is-opened')) {
$this.addClass('is-closed').removeClass('is-opened');
} else {
$this.removeClass('is-closed').addClass('is-opened');
}
};
//attaching the event to both, together.
$('#menu-burger-wrapper, ul.menu-item li').on('click', clickHandler);
You can use toggleClass to toggle class.
You can use , to separate the elements on which you want to bind event.
$('#menu-burger-wrapper, .menu-item').on('click', function (e) {
e.preventDefault();
$(this).toggleClass('is-opened is-closed');
});
$('.menu-item').on('click', 'li', function() {
$('#menu-burger-wrapper').trigger('click');
});
Demo: https://jsfiddle.net/tusharj/7c5nd7rj/1/