How to change dropdown arrow image with javascript - javascript

I am trying to make a dropdown navigation menu where I am using arrow up and down images for the dropdown links. What I want is that when I click on a dropdown link means when I open the submenu, the arrow image should be the arrow-up image and when I close the submenu, it will go back to the arrow-down image. I have more than one dropdown link with the arrow images. The problem is that when I click on one of the dropdown links, the other link with an arrow image also gets triggered and changes. But I only want to change the image of one that I clicked. You can see and check the code below.
const nav__items = document.querySelectorAll(".nav__items");
const nav__list = document.querySelector(".nav__list");
function toggleSubMenu() {
if (this.classList.contains("nav__list--sub-active")) {
this.classList.remove("nav__list--sub-active")
} else if (nav__list.querySelector(".nav__list--sub-active")) {
nav__list
.querySelector(".nav__list--sub-active")
.classList.remove("nav__list--sub-active");
this.classList.add("nav__list--sub-active");
} else {
this.classList.add("nav__list--sub-active");
}
}
function toggleArrowUpDown() {
if (this.classList.contains("nav__list--sub-active")) {
document.querySelectorAll('.arrow_down').forEach((arrow) => {
arrow.src = "https://i.postimg.cc/Bb4ttXfk/arrow-up.png"
})
} else {
document.querySelectorAll('.arrow_down').forEach((arrow) => {
arrow.src = "https://i.postimg.cc/Hn9ctbtT/arrow-down.png"
})
}
}
for (let item of nav__items) {
if (item.querySelector(".nav__list--sub")) {
item.addEventListener('click', toggleSubMenu, false);
item.addEventListener('click', toggleArrowUpDown, false);
}
}
* {
box-sizing: border-box;
text-decoration: none;
list-style: none;
}
.nav__list {
margin: 0;
padding: 0;
}
.nav__items {
padding-bottom: 2em;
}
.nav__list--sub {
display: none;
}
.nav__list--sub-active .nav__list--sub {
display: block;
}
<nav class="nav">
<div class="container">
<ul class="nav__list">
<li class="nav__items">
Home
</li>
<li class="nav__items has-submenu">
<a tabindex="0">About <img src="https://i.postimg.cc/Hn9ctbtT/arrow-down.png" class="arrow_down" alt=""
/></a>
<ul class="nav__list--sub">
<li class="nav__items--sub sub-item">
<a href="#">Public Engagement
</a>
<ul class="nav__list--sub-sub">
<li>Cultural Map</li>
<li>Child Culture</li>
<li>Initiatives</li>
<li>Membership</li>
</ul>
</li>
<li class="nav__items--sub">Events</li>
<li class="nav__items--sub">
Publications
</li>
</ul>
</li>
<li class="nav__items has-submenu">
<a tabindex="0">Programs & Initiatives <img src="https://i.postimg.cc/Hn9ctbtT/arrow-down.png" class="arrow_down" alt=""
/></a>
<ul class="nav__list--sub">
<li class="nav__items--sub sub-item">
<a href="#">Public Engagement
</a>
</li>
<li class="nav__items--sub sub-item">
<a href="#">Events
</a>
</li>
<li class="nav__items--sub">
Publications
</li>
</ul>
</li>
</ul>
</div>
</nav>

Instead of document.querySelectorAll in your toggleArrowUpDown() method, change that to this.querySelectorAll so you're only querying on this instead of the entire document.
But you can also take this one step further and use CSS classes to manage the display, so you only need to toggle the class.
const nav__items = document.querySelectorAll(".nav__items");
const nav__list = document.querySelector(".nav__list");
function toggleSubMenu() {
if (this.classList.contains("nav__list--sub-active")) {
this.classList.remove("nav__list--sub-active")
} else if (nav__list.querySelector(".nav__list--sub-active")) {
nav__list
.querySelector(".nav__list--sub-active")
.classList.remove("nav__list--sub-active");
this.classList.add("nav__list--sub-active");
} else {
this.classList.add("nav__list--sub-active");
}
}
function toggleArrowUpDown() {
let spanClasses = this.querySelector('span').classList;
if (this.classList.contains("nav__list--sub-active")) {
spanClasses.remove('arrow_down');
spanClasses.add('arrow_up');
} else {
spanClasses.remove('arrow_up');
spanClasses.add('arrow_down');
}
}
for (let item of nav__items) {
if (item.querySelector(".nav__list--sub")) {
item.addEventListener('click', toggleSubMenu, false);
item.addEventListener('click', toggleArrowUpDown, false);
}
}
* {
box-sizing: border-box;
text-decoration: none;
list-style: none;
}
.nav__list {
margin: 0;
padding: 0;
}
.nav__items {
padding-bottom: 2em;
}
.nav__list--sub {
display: none;
}
.nav__list--sub-active .nav__list--sub {
display: block;
}
.arrow_down {
background-image: url('https://i.postimg.cc/Hn9ctbtT/arrow-down.png');
width: 12px;
height: 9px;
display: inline-block;
background-repeat: no-repeat;
}
.arrow_up {
background-image: url('https://i.postimg.cc/Bb4ttXfk/arrow-up.png');
width: 12px;
height: 9px;
display: inline-block;
background-repeat: no-repeat;
}
<nav class="nav">
<div class="container">
<ul class="nav__list">
<li class="nav__items">
Home
</li>
<li class="nav__items has-submenu">
<a tabindex="0">About <span class="arrow_down" alt=""
></span></a>
<ul class="nav__list--sub">
<li class="nav__items--sub sub-item">
<a href="#">Public Engagement
</a>
<ul class="nav__list--sub-sub">
<li>Cultural Map</li>
<li>Child Culture</li>
<li>Initiatives</li>
<li>Membership</li>
</ul>
</li>
<li class="nav__items--sub">Events</li>
<li class="nav__items--sub">
Publications
</li>
</ul>
</li>
<li class="nav__items has-submenu">
<a tabindex="0">Programs & Initiatives <span class="arrow_down" alt=""
></span></a>
<ul class="nav__list--sub">
<li class="nav__items--sub sub-item">
<a href="#">Public Engagement
</a>
</li>
<li class="nav__items--sub sub-item">
<a href="#">Events
</a>
</li>
<li class="nav__items--sub">
Publications
</li>
</ul>
</li>
</ul>
</div>
</nav>

Related

Keep sub menu open on hover with javascript

Description : I got a nav bar with my menu and submenu. I use javascript to make the submenu appear on click
Here is my html
<ul class="menu grid-x">
<div class="logo align-self-middle">
LOGO
</div>
<li class="item has-submenu align-self-middle grid-x align-middle">
<a tabindex="0">Société</a>
<ul class="submenu">
<li class="subitem text-left">Présentation</li>
<li class="subitem text-left">Nous rejoindre</li>
<li class="subitem has-submenu text-left"><a tabindex="0">Nos agences</a></li>
<li class="subitem text-left">Nos actualités</li>
</ul>
</li>
<li class="item has-submenu align-self-middle">
<a tabindex="0">Téléphonie</a>
<ul class="submenu">
<li class="subitem text-left">Téléphonie entreprise</li>
<li class="subitem text-left">Flotte mobile</li>
<li class="subitem text-left">Communications unifiées</li>
<li class="subitem text-left">Centre de contact virtuel</li>
<li class="subitem text-left">Centre de contact Multicanal</li>
</ul>
</li>
<ul>
And here is the javascript I use
const items = document.querySelectorAll(".item");
const menu = document.querySelector(".menu");
/* Activate Submenu */
function toggleItem() {
if (this.classList.contains("submenu-active")) {
this.classList.remove("submenu-active");
} else if (menu.querySelector(".submenu-active")) {
menu.querySelector(".submenu-active").classList.remove("submenu-active");
this.classList.add("submenu-active");
} else {
this.classList.add("submenu-active");
}
}
/* Event Listeners */
for (let item of items) {
if (item.querySelector(".submenu")) {
item.addEventListener("click", toggleItem, false);
item.addEventListener("keypress", toggleItem, false);
}
}
And the CSS to make the submenu appear when parent receive the submenu-active class
submenu-active .submenu {
display: block;
position: absolute;
left: 0;
top: 100%;
min-width: 200px;
}
Problem : I would like to make the submenu appear on hover. The mouseover works when I hover the item class div, but submenu disappear when I try to click on one of its elements because I'm not maintaining the item div hover.
I don't want to use jquery and can't figure out a solution. Anyone could help ?
Thanks a lot
Try this code! and add style as you want.
You can include more mouse events add class on hover OR click is up to you.
const items = document.querySelectorAll(".item");
const menu = document.querySelector(".menu");
items.forEach(item => {
item.addEventListener('click', function() {
if ( !item.classList.contains("show") ){
item.classList.add("show")
}else {
item.classList.remove("show")
}
})
})
.has-submenu {
position: relative; }
.submenu {
display: none;
background-color: #ffffff;
position: absolute;
left: 0;
top: 100%;
min-width: 200px;
}
.has-submenu.show .submenu {
display: block ;
}
<ul class="menu grid-x">
<div class="logo align-self-middle">
LOGO
</div>
<li class="item has-submenu align-self-middle grid-x align-middle ">
<a tabindex="0">Société</a>
<ul class="submenu ">
<li class="subitem text-left">Présentation</li>
<li class="subitem text-left">Nous rejoindre</li>
<li class="subitem has-submenu text-left"><a tabindex="0">Nos agences</a></li>
<li class="subitem text-left">Nos actualités</li>
</ul>
</li>
<li class="item has-submenu align-self-middle">
<a tabindex="0">Téléphonie</a>
<ul class="submenu">
<li class="subitem text-left">Téléphonie entreprise</li>
<li class="subitem text-left">Flotte mobile</li>
<li class="subitem text-left">Communications unifiées</li>
<li class="subitem text-left">Centre de contact virtuel</li>
<li class="subitem text-left">Centre de contact Multicanal</li>
</ul>
</li>
<ul>

Change the position of the <li> using a display:flex not working

I want to change the position of the "li" using a display:flex , but it is not working. How to solve this problem?
.testul li {
display: flex;
flexible direction: column;
}
.test ul li: nth child (1) {
blue background;
order: 2;
}
.test ul li: nth child (2) {
blue background;
order: 1;
}
<div class = "test">
<ul class = "rgsize small" style = "display: block;">
<li class = "attr-conf -">
<a href = "" class = "attr-cls attr-cls-230">
Select the test</a>
</li>
<li class = "attr-conf-587" style = "display: list item;">
<a href = "" class = "attr-cls attr-cls-230 acmtlist">
test</a>
</li>
<li class = "attr-conf-563" style = "display: list item;">
test
</li>
<li class = "attr-conf-566" style = "display: list item;">
<a href = "javascript: void (0);" class="attr-cls attr-cls-230">
test</a>
</li>
</ul>
</div>
If you want to display each li side by side, then you need to consider the ul as the container, so you'll have to do something like:
.test ul {
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 20px;
}
<div class="test">
<ul class="rgsize small">
<li class="attr-conf -">
<a href="" class="attr-cls attr-cls-230">
Select the test</a>
</li>
<li class="attr-conf-587" style="display: list item;">
<a href="" class="attr-cls attr-cls-230 acmtlist">
test</a>
</li>
<li class="attr-conf-563" style="display: list item;">
test
</li>
<li class="attr-conf-566" style="display: list item;">
<a href="javascript: void (0);" class="attr-cls attr-cls-230">
test</a>
</li>
</ul>
</div>
Furthermore, you have some syntax errors in your CSS, such as a missing space .testul li and wrong order blue background; (should be background: blue;).
For example, i want to change the position of the "li" using css
<li class="attr-conf-563" style="display: list item;">
test2
</li>
<li class="attr-conf-566" style="display: list item;">
<a href="javascript: void (0);" class="attr-cls attr-cls-230">
test1</a>
</li>
Change the "test1" to "test2"
I think this is the effect you are trying to get
.test > ul {
display: flex;
flex-direction: column;
}
.test ul li:nth-child(even) {
background-color: blue;
order: 2;
}
.test ul li {
padding: 20px;
list-style: none;
}

Auto collapse sidebar menu list when lost focus

I just want to ask :
how to make the dropdown-menu collpase when the dropdown menu is active?
When the mouse hovers to the sidebar, the active dropdown menu expanded again?
i think i just wondering using hover but it doesnt work when i try it, so i hope someone can help me to solve this?
Simple Concept I Just want :
Mouse:hover to sidebar-icon/burger is clicked => sidebar-expanded => menu list that have:submenu clicked => dropdown-menu displayed => mouseOut from sidebar => icon is-collapsed
Mouse:hover to sidebar-icon again / sidebar:state(active) => dropdown menu is already expanded
well i dont know that you can understand my question or something.. but i hope u can make this auto collapse menu
$(document).ready(function() {
// Sidebar links
$('.sidebar .side-list li a').on('click', function() {
const $this = $(this);
if ($this.parent().hasClass('buka')) {
$this
.parent()
.children('.dropdown-menu')
.slideUp(200, () => {
$this.parent().removeClass('buka');
});
} else {
$this
.parent()
.parent()
.children('li.buka')
.children('.dropdown-menu')
.slideUp(200);
$this
.parent()
.parent()
.children('li.buka')
.children('a')
.removeClass('buka');
$this
.parent()
.parent()
.children('li.buka')
.removeClass('buka');
$this
.parent()
.children('.dropdown-menu')
.slideDown(200, () => {
$this.parent().addClass('buka');
});
}
});
// ٍSidebar Toggle
$('.burger').on('click', e => {
$('.konten').toggleClass('k-kebuka');
$('.sidebar').toggleClass('s-kebuka');
e.preventDefault();
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="sidebar" class="sidebar bg-cerah">
<div class="sidebar-dalem">
<div class="side-konten">
<ul class="side-list">
<li class="side-item dropdown">
<a class="dropdown-toggle" href="javascript:void(0)">
<span class="side-ikon">ICON</span>
<span class="side-judul">MENU</span>
<span class="panah">[>]</span>
</a>
<ul class="dropdown-menu">
<li>
SUBMENU #1
</li>
<li>
SUBMENU #2
</li>
</ul>
</li>
<li class="side-item dropdown">
<a class="dropdown-toggle" href="javascript:void(0)">
<span class="side-ikon">[X]</span>
<span class="side-judul">MENU #2</span>
<span class="panah">[>] ></span>
</a>
<ul class="dropdown-menu">
<li>
SUBMENU #1
</li>
<li>
SUBMENU #2
</li>
</ul>
</li>
<li class="side-item">
<a class="side-link" href="javascript:void(0)">
<span class="side-ikon">[X]</span>
<span class="side-judul">MENU #3</span>
</a>
</li>
</ul>
</div>
</div>
</div>
<div id="konten" class="konten">
<div class="konten-navbar sticky-top">
<ul class="navbar-kiri">
<li>
<a id="burger" href="javascript:void(0)" class="burger">BURGER ICO</a>
</li>
<li>
SEARCH ICO
</li>
</ul>
</div>
</div>
In pure CSS, .menu:hover definitely works, but you have to build the entire menu inside of the element that has the :hover pseudo class and also either touching or overlapping:
.popup {
position: relative;
}
button {
width: 8em;
height: 40px;
}
ul {
position: absolute;
top: 36px;
left: 8px;
background: #eee;
border: 1px solid black;
display: none;
margin: 0;
width: 14em;
min-height: 8em;
padding: 0.5em;
list-style: none;
}
.popup:hover ul {
display: block;
}
<div>
<div class="popup"><button>Menu</button>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div>
</div>
Certainly, you'd need to style everything properly.
I also seem to remember that JQuery has OnMouseEnter and OnMouseLeave events that work kind of like :hover too.

togggle menu need to open on click and close itself when click the other menu

How can make it make
1- open toggle menu when on click menu (not opened by default)
2- close itself - if click other parent menu
trying to make it work for the project
and i copied from cssdesk
$('.inbox li').click(function(e) {
$('.inbox li.active').removeClass('active');
var $this = $(this);
if (!$this.hasClass('active')) {
$this.addClass('active');
}
e.preventDefault();
});
$(document).ready(function () {
$('.tree-toggler').click(function () {
$(this).parent().children('ul.tree').toggle(300);
});
});
<link class="cssdeck" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap.min.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap-responsive.min.css" class="cssdeck">
<ul class="inbox-nav nav" style="border-top: 1px solid #eef1f5; margin-top:10px;" >
<li class="">
<a href="javascript:;" id="fldr3">menu 1
</li>
<li class="">
<a data-title="Inbox" data-type="important" href="javascript:;">2nd Menu</a>
</li>
<li class="">
<a data-title="Sent" data-type="sent" href="javascript:;">menu2</a>
</li>
<li class="divider"></li>
<li class="active tree-toggler">
Toggle menu</li>
<ul class="nav nav-list tree">
<li class="">Link</li>
<li class="">Link</li>
</ul>
</li>
</ul>
<script class="cssdeck" src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script class="cssdeck" src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/js/bootstrap.min.js"></script>
If user click is not neccesary you can do it by CSS, this is an example the 4th menu item has sub menu items
.menu,
.menu-item {
display: inline;
cursor: default;
}
.menu-item.has-subItem {
position: absolute;
}
.menu-item ul {
display: none;
position: absolute;
top: 15px;
left: 0;
padding: 0;
}
.menu-item:hover ul {
display: inline;
}
<ul class='menu'>
<li class='menu-item'>Item 1</li>
<li class='menu-item'>Item 2</li>
<li class='menu-item'>Item 3</li>
<li class='menu-item has-subItem'>Item 4
<ul>
<li class='sub-item'>sub 1</li>
<li class='sub-item'>sub 2</li>
<li class='sub-item'>sub 3</li>
</ul>
</li>
</ul>
In your $('.inbox li').click() function use jquery's .hide() function on the ul.tree element. Since .hide() won't do anything if the element is already hidden, you don't need to check if it needs to be hidden.
(Similarly, you can pull the $this.addClass('active'); statement out of the if, since it simply won't do anything if the class is already added!)

jQuery toggle image not switching

I have created expandable links where the arrow changes when you expand the link. Expandable works great and the arrow keeps changing correctly when I expand the other link. It doesn't switch correctly if I expand the same link.
Here is a demo.
HTML
<ul class="side-expand">
<li class="expandor">
<a class="adobe" href="#" id="vid_link3">Adobe Digital Editions</a>
<ul>
<li>
<a href="#" id="link22"><i class="icon-video"></i>
Introduction</a>
</li>
</ul>
</li>
<li class="expandor">
<a class="android" href="#" id="vid_link4">Android</a>
<ul>
<li>
<a href="#" id="link29"><i class="icon-video"></i>
Introduction</a>
</li>
</ul>
</li>
</ul>
JAVASCRIPT
$('.expandor > a:first-child').click(function(e) {
e.preventDefault();
var $this = $(this).next('ul');
$(".side-expand li ul").not($this).slideUp();
$this.slideToggle();
$('.side-expand > li').css('background-color', 'transparent');
$('.side-expand > li').removeClass('dexpandor');
var visibleUL = $('.side-expand li').find('ul').is(':visible');
if (visibleUL) {
$(this).parent('li').css('background-color', 'transparent', 'font-weight', 'normal').addClass('dexpandor');
}
});
arrow not changing for the same toggle
Replacing lines 8 through 13 with the following should toggle your arrow class properly:
$(this).parent().siblings().removeClass('dexpandor');
$(this).parent().toggleClass('dexpandor');
Add the class change code in slideToggle() callback. Because the ul is hidden only when slide is complete, which is when you need to remove the class.
DEMO
$('.expandor > a:first-child').click(function(e) {
e.preventDefault();
var $this = $(this).next('ul');
$(".side-expand li ul").not($this).slideUp();
$this.slideToggle(function() {
$('.side-expand > li').css('background-color', 'transparent');
$('.side-expand > li').removeClass('dexpandor');
var visibleUL = $(this).closest('li').find('ul').is(':visible');
if (visibleUL) {
$(this).parent('li').css('background-color', 'transparent', 'font-weight', 'normal').addClass('dexpandor');
}
});
});
.side-expand li ul {
display: none;
}
.expandor {
background-image: url("https://odhelp.blob.core.windows.net/content/artifacts/img/right-arrow-small.png");
}
.expandor,
.dexpandor {
background-color: transparent;
background-position: right 13px;
background-repeat: no-repeat;
}
.dexpandor {
background-image: url("https://odhelp.blob.core.windows.net/content/artifacts/img/down-arrow-small.png");
}
.side-expand li a {
font-size: 14px;
font-weight: normal;
padding-left: 70px;
}
.side-expand li a {
background-size: 25px auto !important;
border-bottom: 1px solid rgb(235, 235, 235);
color: #000;
display: block;
font-size: 15px;
padding: 5px 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="side-expand">
<li class="expandor">
<a id="vid_link3" value="6plk07k8op" href="#" class="adobe">Adobe Digital Editions</a>
<ul>
<li><a value="6plk07k8op" href="#" id="link22"><i class="icon-video"></i> Introduction</a></li>
<li><a value="q1kogk5dc2" href="#" id="link23"><i class="icon-video"></i> Install</a></li>
<li><a value="zmdge1whxu" href="#" id="link24"><i class="icon-video"></i> Authorize your computer</a></li>
<li><a value="snl5pnvv27" href="#" id="link25"><i class="icon-video"></i> Read eBooks</a></li>
<li><a value="8ldljcbtw0" href="#" id="link26"><i class="icon-video"></i> Return eBooks </a></li>
<li><a value="tfrp7xjgus" href="#" id="link27"><i class="icon-video"></i> Transfer eBooks to reader </a></li>
<li><a value="men1mw9an3" href="#" id="link28"><i class="icon-video"></i> Remove eBooks from reader</a></li>
</ul>
</li>
<li class="expandor">
<a id="vid_link4" value="ayfssj4211" href="#" class="android">Android</a>
<ul>
<li><a value="ayfssj4211" href="#" id="link29"><i class="icon-video"></i> Introduction </a></li>
<li><a value="aqv1ieh6zd" href="#" id="link30"><i class="icon-video"></i> Install the OverDrive app</a> </li>
<li><a value="ospa26ccnh" href="#" id="link37"><i class="icon-video"></i> Return and share titles</a></li>
</ul>
</li>
</ul>
Add this to the click event, it toggle the class :
$(this).parent('li').css('background-color','transparent', 'font-weight', 'normal').toggleClass('dexpandor','expandor');
Demo : jsfiddle

Categories

Resources