I have a dropdown menu working but I can't figure out how to close the previous menu onclick. All the menues stay open so I need them to close when a different menu is open.
Please see my jsfiddle
https://jsfiddle.net/yvhnphp4/
$(document).ready(function(){
// Dropdown menu
var findDropdowns = document.querySelectorAll(".has-dropdown");
for(var i = 0; i < findDropdowns.length; i++) {
if(i == 0) {
var dropdownId = "has-dropdown-1";
findDropdowns[i].setAttribute("id", dropdownId);
}else {
var addOneToIndex = i + 1;
dropdownId = "has-dropdown-" + addOneToIndex;
findDropdowns[i].setAttribute("id", dropdownId);
}
var targetDropdown = document.getElementById(dropdownId);
targetDropdown.onclick = dropdownTrigger;
}
function dropdownTrigger(e) {
e.preventDefault();
var showHideDropdown = e.target.nextElementSibling;
showHideDropdown.setAttribute("class", "show");
}
});
<ul class="nav">
<li><a class="has-dropdown" href="">Link</a>
<ul>
<li>Sub-Link</li>
<li>Sub-Link</li>
<li>Sub-Link</li>
</ul>
</li>
<li><a class="has-dropdown" href="">Link</a>
<ul>
<li>Sub-Link</li>
<li>Sub-Link</li>
<li>Sub-Link</li>
</ul>
</li>
</ul>
.nav ul {display:none;}
.nav ul.show{display:block;}
You can simply remove the .show class from all ul tags in .nav that still have it, before opening a new dropdown:
function dropdownTrigger(e) {
var opened = document.querySelectorAll(".nav ul.show");
for(var i = 0; i < opened.length; i++) {
opened[i].removeAttribute("class");
}
...
}
Note that since you're using jQuery anyway ($(document).ready) there is probably a much better way to do this.
Also, use href="#" instead of href="".
Related
I am making an Off Canvas sidebar dropdown menu in vanilla JS.
Almost at the bottom of my JS code I have made a function to hide the sidebar off canvas just after someone clicks an href link.
Also I have made a function to hide and show the hidden submenu level of the dropdown menu in order to click them.
But now I need a function to close every opened dropdown menu from the sidebar when a user clicks an href link, just before getting the user to anoher site page. Then, when the user opens again the menu all dropdowns will be closed.
NOTE: 'aTags' is the name of the variable that points to every clickeable href element
Any advice will be very helpfull!
const open = document.querySelector('.open');
let list_items = document.querySelectorAll('#subb');
let overlay = document.querySelector('.overlay');
let aTags = open.getElementsByClassName('ilink');
// Show and Hide sidebar when click icon
let toggles = document.querySelectorAll(".c-hamburger");
for (let i = toggles.length - 1; i >= 0; i--) {
let toggle = toggles[i];
toggleHandler(toggle);
};
function toggleHandler(toggle) {
toggle.addEventListener("click", function(e) {
e.preventDefault();
if (this.classList.contains("is-active") === true) {
this.classList.remove("is-active");
open.classList.remove('oppenned');
overlay.className = 'overlay';
} else {
this.classList.add("is-active");
open.classList.add('oppenned');
overlay.className += ' open';
}
});
window.addEventListener('click', function(event) {
if (event.target === overlay) {
toggle.classList.remove("is-active");
open.classList.remove('oppenned');
overlay.className = 'overlay';
}
});
// hide sidebar off canvas when click a menu link
for (let i = 0; i < aTags.length; i++) {
aTags[i].addEventListener("click", close);
}
function close(e) {
e.stopPropagation();
open.classList.remove('oppenned');
toggle.classList.remove("is-active");
overlay.className = 'overlay';
}
// Show and Hide the hidden Submenu ul
for (let i = 0; i < list_items.length; i++) {
list_items[i].addEventListener("click", show);
}
function show(e) {
e.stopPropagation();
this.classList.toggle("myClass");
}
}
.sub-menu ul ul {
max-height: 0;
position: relative;
top: 0;
left: 0;
opacity: 0;
visibility: hidden;
transition: all 0.6s ease-out;
background: white;
}
#subb.myClass>ul {
max-height: 32em;
visibility: visible;
opacity: 1;
}
<nav id="nav" class="sub-menu open">
<ul class="list-unstyled">
<li id="subb">
<a class="link">Soluciones</a>
<ul>
<li id="subb">
<a class="link">Correo y herramientas colaborativas</a>
<ul>
<li><a class="link ilink" href="https://www.google.com/">Google Workspace</a></li>
<li><a class="link ilink href=" https://www.google.com/ "">Google for Education</a></li>
<li><a class="link ilink" href="https://www.google.com/">Microsoft 365</a></li>
</ul>
</li>
</ul>
I've been trying to figure this out for hours. I currently have a fixed nav for my anchor website. I would like the menu link background color to change when scrolling through each section. Like this: https://codepen.io/dbilanoski/pen/LabpzG . When I scroll through each section I only see the hover background color not the active state color. If you have any tips or advice, please advise.
Thank you!
var navLink = $(".nav-link"),
topMenuHeight = navLink.outerHeight() + 15,
//All list items
menuItems = navLink.find("a"),
//Anchors corresponding to menu items
scrollItems = menuItems.map(function() {
var item = $($(this).attr("href"));
if (item.length) {
return item;
}
});
// Bind click handler to menu items
// so we can get a fancy scroll animation
menuItems.click(function(e) {
var href = $(this).attr("href")
offsetTop = href === "#" ? 0 : $(href).offset().top - topMenuHeight + 1;
$('html, body').stop().animate({
scrollTop: offsetTop
}, 300);
e.preventDefault();
});
// Bind to scroll
$(window).scroll(function() {
// Get container scroll position
var fromTop = $(this).scrollTop() + topMenuHeight;
// Get id of current scroll item
var cur = scrollItems.map(function() {
if ($(this).offset().top < fromTop)
return this;
});
// Get the id of the current element
cur = cur[cur.length - 1];
var id = cur && cur.length ? cur[0].id : "";
if (navLink !== id) {
navLink = id;
// Set/remove active class
menuItems
.parent().removeClass("active")
.end().filter("[href='#" + id + "']").parent().addClass("active");
}
});
a {
color: inherit;
text-decoration: none;
}
a:hover {
color: #fa448c;
text-decoration: underline;
}
a:active {
background-color: #fa448c;
color: #fff;
}
li {
list-style-type: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="menu">
<ul class="nav-list">
<li class="nav-item">
Home
</li>
<li class="nav-item">
Products
</li>
<li class="nav-item">
Featured
</li>
<li class="nav-item">
Best Sellers
</li>
<li class="nav-item">
Contact
</li>
</ul>
</div>
The trick of the codepen you've sent is that all sections have the same height. However, there's a more flexible way of doing that. Using this solution, you check for each section whether it's shown on the screen or not, and if it is, highlight its button in the navlist.
Could manage so far the things I wanted to achieve for my mega menu. The problem now is, that I forgot that touchscreens don´t really work with hover. So, the mega menu appears on hover with JavaScript. The menu item that triggers the div is the default menu of WordPress/theme. I know I can do it with a JavaScript button. But is it possible to achieve this with that specific default menu "span" li id="menu-item-136" like I achieved the rest of the mega menu styling with JavaScript? Adding a click option to that span? That would be great! Here´s the code so far:
//Showing mega menu on hover over menu point
document.getElementById("menu-item-136").addEventListener("mouseover", mouseOver);
document.getElementById("menu-item-136").addEventListener("mouseout", mouseOut);
function mouseOver() {
document.getElementById("mega-menu").style.display = "block";
}
function mouseOut() {
document.getElementById("mega-menu").style.display = "none";
}
//Let mega menu stay visible when hovering over it
//Style menupoint when hovering over mega menu div
document.getElementById("mega-menu").addEventListener("mouseover", mouseOver);
document.getElementById("mega-menu").addEventListener("mouseout", mouseOut);
function mouseOver() {
document.getElementById("mega-menu").style.display = "block";
var labels = document.getElementsByClassName("aux-menu-label");
for (var i = 0; i < labels.length; i++) {
labels[0].style.color = "yellow"
}
}
function mouseOut() {
document.getElementById("mega-menu").style.display = "none";
var labels = document.getElementsByClassName("aux-menu-label");
for (var i = 0; i < labels.length; i++) {
labels[i].style.color = "blue"
}
}
.menu-item-136 {
background-color: grey;
height: 50px;
}
.menu-item-136:hover {
background-color: green;
}
.aux-menu-label {
color: blue;
}
.mega-menu-1 {
display: none;
background-color: green;
height: 200px;
}
<div>
<li id="menu-item-136" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-136 aux-menu-depth-0 aux-menu-root-2 aux-menu-item">
<a href="#" class="aux-item-content">
<span class="aux-menu-label"><i aria-hidden="true" class="services auxicon-list"></i> Leistungen</span>
<span class="aux-submenu-indicator"></span></a>
</div>
<div id="mega-menu" class="mega-menu-1">content</div>
Thanks for your help! :)
Sure #Artan
document.getElementById('menu-item-136').addEventListener('click',function(){
document.getElementsByClassName("aux-menu-label")[0].style.backgroundColor = 'yellow';
});
<div>
<li id="menu-item-136" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-136 aux-menu-depth-0 aux-menu-root-2 aux-menu-item">
<a href="#" class="aux-item-content">
<span class="aux-menu-label"><i aria-hidden="true" class="services auxicon-list"></i> Leistungen</span>
<span class="aux-submenu-indicator"></span></a>
</div>
I am making a chrome extension and have this in my popup.html:
<nav id="secondary-nav">
<ul>
<li class="active">Prerender</li>
<li>Prefetch</li>
<li>Preconnect</li>
</ul>
</nav>
What I want to do is to change the active link onclick in pure JS. How and where can I do that?
Should I make it in the background.js?
Thank you.
According to the Google Developper documentation you can link any other JS file to your main html file.
<!DOCTYPE html>
<html>
...
<body>
<script src="popup.js"></script>
</body>
</html>
And if you want to set the <li> active when you click on it, you should use something like this :
var menu = document.getElementById("menu");
var menu_items = menu.children;
for (var i = 0; i < menu_items.length; i++) {
menu_items[i].onclick = function() {
this.classList.add("active");
// don't forget to reset the class of others
for (var j = 0; j < menu_items.length; j++) {
if (menu_items[j] != this) menu_items[j].classList.remove("active");
}
}
}
li.active {
color: green;
}
<ul id="menu">
<li class="active">link1</li>
<li>link2</li>
<li>link3</li>
<li>link4</li>
</ul>
I am new to javascript and am having trouble with menus. I can get a flyout menu to work, and I can get a scrolling menu to work (demo of scrolling menu http://css-tricks.com/examples/LongDropdowns/).
However, I cannot figure out how to merge the effects. Can someone please help me with the flyout code for below?
//HTML
<ul class="dropdown">
<li>CITIES BY STATE
<ul>
for (var p = 0; p < state.length; p++) {
<li> + states[p][0] + "");
<ul id="city\" class="city">
<li>CITY 1</li>
<li>CITY 2</li>
<li>CITY 3</li>
</ul>");
</li>");
}
</ul>
</ul>
</li>
//SCRIPT TO ALLOW SCROLL THROUGH LIST
<script>
var maxHeight = 600;
$(function(){
$(".dropdown > li").hover(function() {
var $container = $(this),
$list = $container.find("ul"),
$anchor = $container.find("a"),
height = $list.height() * 1.1, // make sure there is enough room at the bottom
multiplier = height / maxHeight; // needs to move faster if list is taller
// need to save height here so it can revert on mouseout
$container.data("origHeight", $container.height());
// so it can retain it's rollover color all the while the dropdown is open
$anchor.addClass("hover");
// don't do any animation if list shorter than max
if (multiplier > 1) {
$container
.css({
height: maxHeight,
overflow: "hidden"
})
.mousemove(function(e) {
var offset = $container.offset();
var relativeY = ((e.pageY - offset.top) * multiplier) - ($container.data("origHeight") * multiplier);
if (relativeY > $container.data("origHeight")) {
$list.css("top", -relativeY + $container.data("origHeight"));
};
});
}
}, function() {
var $el = $(this);
// put things back to normal
$el
.height($(this).data("origHeight"))
.find("ul")
.css({ top: 0 })
.show()
.find("a")
.removeClass("hover");
});
});
</script>
This is what I have tried, but I am off. I want a list of cities to display to the right of the state list when I hover on a state.
/*code to show/hide city menu*/
#city li:hover ul ul, #city li:hover ul ul ul, #city li:hover ul ul ul ul{
display:none;
}
#city li:hover ul, #city li li:hover ul, #city li li li:hover ul, #city li li li li:hover ul{
display:block;
}
Chrisoph is right. This is just jibberish:
<ul class="dropdown">
<li>CITIES BY STATE
<ul>
for (var p = 0; p < state.length; p++) {
<li> + states[p][0] + "");
<ul id="city\" class="city">
<li>CITY 1</li>
<li>CITY 2</li>
<li>CITY 3</li>
</ul>");
</li>");
}
</ul>
</ul>
</li>
This is syntactially correct HTML/Javascript. Screw it... I decided to just code it for you because I'm bored, but you really need to go back to basics in HTML/JavaScript.
<html>
<head>
<title>test</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function()
{
var map = [
{state: "NSW", cities: ["Sydney", "Newcastle", "Orange"]},
{state: "QLD", cities: ["Brisbane", "Cairns", "Townsville"]},
{state: "VIC", cities: ["Melbourne", "Geelong", "Ballarat"]},
{state: "SA", cities: ["Radelaide", "Mount Gambier"]},
{state: "TAS", cities: ["Hobart", "Devonport", "Launceston"]}
];
for (var i = 0; i < map.length; i++)
{
var a = $('<a href="#">').html(map[i].state);
var li = $('<li>').append(a);
var cities = $('<ul>').attr('id', map[i].state).addClass('cityList');
for(var j = 0; j < map[i].cities.length; j++)
{
cities.append($('<li>').html(map[i].cities[j]));
}
li.append(cities);
$('#citiesByState').append(li);
}
});
</script>
</head>
<body>
<ul class="dropdown">
<li>
CITIES BY STATE
<ul id="citiesByState"></ul>
</li>
</ul>
</body>
</html>
Now go back and fix your question and test it then we'll look at any new problems.