HTML code from menu:
<ul id="sidebarMenu" class="nav nav-sidebar" data-nav-type="accordion">
<li class="nav-item nav-item-submenu nav-item-expanded nav-item-open">
<i class="fad fa-user-tie fa-fw mr-2"></i>Webadmin
<ul class="nav nav-group-sub">
<li class="nav-item nav-item-submenu nav-item-expanded nav-item-open"><i class="fas fa-abacus mr-2"></i>tester
<ul class="nav nav-group-sub">
<li class="nav-item nav-item-submenu nav-item-expanded nav-item-open">
<i class="fas fa-abacus mr-2"></i>tester 2
<ul class="nav nav-group-sub">
<li class="nav-item">
<i class="fad fa-cogs fa-fw mr-2"></i>Site instellingen
</li>
</ul>
</li>
</ul>
</li>
<li class="nav-item"><i class="fad fa-list fa-fw mr-2"></i>Menu aanpassen</li>
</ul>
</li>
</ul>
What I want is add a class 'nav-item-expanded nav-item-open' on al related li with class nav-item-submenu.
So if the user is an a page that the menu collapse automatically the sub menus until the link
I have the next code:
This works. But its limited on my script this wil go back for 5 subs. But if the user want to use by example 6 menus the script fails. Sorry for my bad writing: D
$('.nav-item > a.active')
.closest('.nav-item-submenu')
.addClass('nav-item-expanded nav-item-open')
.parent()
.closest('.nav-item-submenu')
.addClass('nav-item-expanded nav-item-open')
.parent()
.closest('.nav-item-submenu')
.addClass('nav-item-expanded nav-item-open')
.parent()
.closest('.nav-item-submenu')
.addClass('nav-item-expanded nav-item-open')
.parent()
.closest('.nav-item-submenu')
.addClass('nav-item-expanded nav-item-open')
how can I simplify this code?
Example that I have tried:
var test = function(data = '') {
if (data === '') {
data = $('.nav-item > a.active').closest('.nav-item-submenu');
} else {
data = data.parent().closest('nav-item-submenu');
}
if (data.length > 0) {
data.addClass('nav-item-expanded nav-item-open');
test(data);
}
};
but that's not working.
You can use .parentsUntil() to simplify this. It returns all ancestors up to a point and can filter them. It takes two parameters:
Selector for the final ancestor to stop at.
Selector to filter the ancestors by.
This is almost the opposite of .find() which will traverse descendants instead. However, .find() will always work at any depth, it does not have a stop conditions like .parentsUntil().
A single call to .parentsUntil('#sidebarMenu', '.nav-item-submenu') will return all ancestor elements that you want - the .nav-item-submenu ones. At that point, you can add the classes you want or manipulate them further, if needed.
$('button').on('click', function() {
$('.nav-item > a.active')
.parentsUntil('#sidebarMenu', '.nav-item-submenu')
.addClass('nav-item-expanded nav-item-open');
})
.nav-item-submenu {
min-height: 50px;
padding: 5px;
border: 1px dashed black;
}
.nav-item-expanded {
border: 2px solid black;
}
.nav-item-open {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="sidebarMenu" class="nav nav-sidebar" data-nav-type="accordion">
<li class="nav-item nav-item-submenu">
A
<ul class="nav nav-group-sub">
<li class="nav-item nav-item-submenu">B1
<ul class="nav nav-group-sub">
<li class="nav-item nav-item-submenu">
C
<ul class="nav nav-group-sub">
<li class="nav-item">
D
</li>
</ul>
</li>
</ul>
</li>
<li class="nav-item">B2</li>
</ul>
</li>
</ul>
<button>Click me</button>
Related
This is how my code looks like:
<div class="header-nav navbar-collapse collapse ">
<ul id="navigation" class=" nav navbar-nav">
<li>
Home
</li>
<li>
About Us
</li>
</ul>
</div>
I've been trying to add the active class to each of them when the user is on that specific page but no succes so far
Tis is how my script looks like:
var i = 0;
[].forEach.call(document.querySelectorAll('li > a'), function(nav) {
console.log(nav.pathname,window.location.pathname);
if (nav.pathname === window.location.pathname){
i = 1;
console.log(i);
nav.classList.add('active')
}
else{
console.log(i)
nav.classList.removeClass('active')
}
})
The active class is set on the "a" not on "li" and i don't know how to fix this. Maybe someone can help me?
In looking at the classes, it looks like you may be using Bootstrap. I added in those libs to the snippet, and updated some of the classes. I also added in another nav item with the href equal to js since that is the pathname for the snippet window. Otherwise it won't add the active class as there would not be a pathname that would be equal.
I also changed the nav items to pills, so you can see the active link easier.
var i = 0;
document.querySelectorAll('ul.nav > li > a').forEach((nav) => {
console.log({
navPathname: nav.pathname,
windowLocationPathname: window.location.pathname,
areEqual: nav.pathname === window.location.pathname,
});
if (nav.pathname === window.location.pathname) {
nav.classList.add('active')
} else {
nav.classList.remove('active')
}
})
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<div class="navbar navbar-light bg-light">
<ul id="navigation" class="nav nav-pills">
<li class="nav-item">
<a class="nav-link" href="index.html">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="js">JS</a>
</li>
<li class="nav-item">
<a class="nav-link" href="about-us.html">About Us</a>
</li>
</ul>
</div>
To target the parent element, you have a few options - my favorite is element.closest(selector) which takes a starting element and finds the closest containing parent that matches selector
let els = document.querySelectorAll('li > a');
els.forEach(el => {
el.addEventListener('click', e => {
els.forEach(a => a.closest('li').classList.remove('active'));
e.target.closest('li').classList.add('active');
})
})
li.active {
background-color: green;
}
<ul>
<li><a href='#'>link 1</a></li>
<li><a href='#'>link 1</a></li>
<li><a href='#'>link 1</a></li>
</ul>
Thanks for this, i merged the two responses and made it into one that works for me, this is the script that worked without even touching the classes into the nav-bar:
document.querySelectorAll('ul.nav > li > a').forEach((nav) => {
console.log({
navPathname: nav.pathname,
windowLocationPathname: window.location.pathname,
areEqual: nav.pathname === window.location.pathname,
});
if (nav.pathname === window.location.pathname) {
nav.closest('li').classList.add('active')
} else {
nav.closest('li').classList.remove('active')
}
})
I wanted to slideToggle menu items with toggleclass, .opened class should be added and removed for menu items. This is working for me when I toggle different menu item but for same menu item when I click this, .opened class won't get removed here is my code
Html menu tag
<ul id="menu-main-menu">
<li class="menu-item"><a href="link_url">text<a>
<ul class="sub-menu">
<li class="menu-item">
<ul class="sub-menu">
<li class="menu-item"><a href="link_url">second sub item<a></li>
</ul>
</li>
<li class="menu-item"><a href="link_url">first sub item<a></li>
<li class="menu-item"><a href="link_url">first sub item<a></li>
</ul>
</li>
<li class="menu-item"><a href="link_url">text<a></li>
</ul>
jquery code
$('.menu-item').on('click', function(e) {
$('.menu-item').removeClass('opened')
$(this).toggleClass('opened');
if ($('.sub-menu', this).length >=1) {
e.preventDefault();
}
$(this).children('ul').slideToggle('fast');
$(this).siblings('li').find('ul').hide('slow')
e.stopPropagation();
});
I am not sure what I am doing wrong. Can you please help me for this?
Thanks
There is a basic mistake in your code.
Close Anchor tags, you have an opening anchor tag on both the ends.
then use the logic to get your result, see the example, If need anything else, please let me know
Add sub items Achor or li text, that depends on your requirement, but for UX you should add some text so users can get that there is still some more content to see.
$('.menu-item').click(function(e){
$(this).siblings().find('> .sub-menu').slideUp();
$(this).find('> .sub-menu').slideToggle();
$(this).siblings().removeClass('opened');
$(this).toggleClass('opened');
e.stopPropagation();
});
.sub-menu {
display: none;
}
.menu-item a{
display: inline-block;
margin-bottom: 10px;
}
.menu-item {
margin-bottom: 10px;
}
.menu-item.hasSubmenu {
border-bottom: 1px solid;
}
.menu-item a {
background-color: red;
color: white;
}
.hasSubmenu {
position: relative;
}
.hasSubmenu:after {
position: absolute;
right: 10px;
top: 0px;
content: "+";
display: block;
font-size: 20px;
font-weight: bold;
}
.hasSubmenu.opened:after {
content: "-";
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="menu-main-menu">
<li class="menu-item hasSubmenu">
text
<ul class="sub-menu">
<li class="menu-item hasSubmenu">
First level
<ul class="sub-menu">
<li class="menu-item">second sub item</li>
<li class="menu-item">second sub item</li>
</ul>
</li>
<li class="menu-item">first sub item</li>
<li class="menu-item">first sub item</li>
</ul>
</li>
<li class="menu-item hasSubmenu">
text
<ul class="sub-menu">
<li class="menu-item hasSubmenu">
First level
<ul class="sub-menu">
<li class="menu-item">second sub item</li>
</ul>
</li>
<li class="menu-item">first sub item</li>
<li class="menu-item">first sub item</li>
</ul>
</li>
</ul>
$('.menu-item').on('click', function(e) {
$(this).toggleClass('opened');
$('.menu-item').not($(this)).removeClass('opened');
if ($('.sub-menu', this).length >= 1) {
e.preventDefault();
}
$(this).children('ul').slideToggle('fast');
$(this).siblings('li').find('ul').hide('slow')
e.stopPropagation();
});
Change the order of removing classes, then skip the current element.
I am in trouble with changing the value of this code. In this code, I wanna change the class "selected" with a number set by JavaScript code.
Briefly speaking, I wanna reach the "li" items and give let say: 4 as a value, and it will add "selected" to the related class and will delete the previous one.
Edit: Additionally, it should also change the < div class="select-box">1< /div> value accordingly.
Here is the code:
<div class="select-container xl" id="_channel">
<label class="select-title T_channel xl">Channel:</label>
<div class="tp-select">
<div class="select-box">1</div>
<div class="select-icon-container"><span class="select-icon"></span></div>
<ul class="drop-down" style="max-height: 204.55px; display: none;">
<li style="cursor: default; border-bottom: 1px solid rgb(204, 204, 204);"></li>
<li data-val="0" class="option-item">Auto</li>
<li data-val="1" class="option-item selected">1</li>
<li data-val="2" class="option-item">2</li>
<li data-val="3" class="option-item">3</li>
<li data-val="4" class="option-item">4</li>
<li data-val="5" class="option-item">5</li>
<li data-val="6" class="option-item">6</li>
<li data-val="7" class="option-item">7</li>
<li data-val="8" class="option-item">8</li>
<li data-val="9" class="option-item">9</li>
<li data-val="10" class="option-item">10</li>
<li data-val="11" class="option-item">11</li>
<li data-val="12" class="option-item">12</li>
<li data-val="13" class="option-item">13</li>
</ul>
</div>
</div>
Thanks;
let x = document.querySelector(".select-box").innerText;
let options = document.querySelectorAll("li.option-item");
options.forEach(item => {
if (item.getAttribute("data-val") == x){
item.classList.add("selected");
}
else{
item.classList.remove("selected");
}
});
console.log(options);
<div class="select-container xl" id="_channel">
<label class="select-title T_channel xl">Channel:</label>
<div class="tp-select">
<div class="select-box">4</div>
<div class="select-icon-container"><span class="select-icon"></span></div>
<ul class="drop-down" style="max-height: 204.55px; display: none;">
<li style="cursor: default; border-bottom: 1px solid rgb(204, 204, 204);"></li>
<li data-val="0" class="option-item">Auto</li>
<li data-val="1" class="option-item selected">1</li>
<li data-val="2" class="option-item">2</li>
<li data-val="3" class="option-item">3</li>
<li data-val="4" class="option-item">4</li>
<li data-val="5" class="option-item">5</li>
<li data-val="6" class="option-item">6</li>
<li data-val="7" class="option-item">7</li>
<li data-val="8" class="option-item">8</li>
<li data-val="9" class="option-item">9</li>
<li data-val="10" class="option-item">10</li>
<li data-val="11" class="option-item">11</li>
<li data-val="12" class="option-item">12</li>
<li data-val="13" class="option-item">13</li>
</ul>
</div>
</div>
Use a query selector that matches the class and data-val value.
// Remove the old selected item
document.querySelectorAll(".option-item.selected").forEach(item => item.classList.remove("selected"));
// Select the desired item
document.querySelector(".option-item[data-val='4']").classList.add("selected");
.option-item.selected {
color: red;
}
<div class="select-container xl" id="_channel">
<label class="select-title T_channel xl">Channel:</label>
<div class="tp-select"><div class="select-box">1</div>
<div class="select-icon-container"><span class="select-icon"></span></div>
<ul class="drop-down" style="max-height: 204.55px;">
<li style="cursor: default; border-bottom: 1px solid rgb(204, 204, 204);"></li>
<li data-val="0" class="option-item">Auto</li>
<li data-val="1" class="option-item selected">1</li>
<li data-val="2" class="option-item">2</li>
<li data-val="3" class="option-item">3</li>
<li data-val="4" class="option-item">4</li>
<li data-val="5" class="option-item">5</li>
<li data-val="6" class="option-item">6</li>
<li data-val="7" class="option-item">7</li>
<li data-val="8" class="option-item">8</li>
<li data-val="9" class="option-item">9</li>
<li data-val="10" class="option-item">10</li>
<li data-val="11" class="option-item">11</li>
<li data-val="12" class="option-item">12</li>
<li data-val="13" class="option-item">13</li>
</ul>
</div>
</div>
you should use getElementsByClassName
So your code will look something like
document.getElementsByClassName("selected")
It sounds like you are looking for nth-child
For example
var selectedElement = document.querySelector(".drop-down:nth-child(4)");
selectedElement.classList.add('selected');
Add an ID to the ul and then select the nth child element.
const selected = 4
documentGetElementById(‘myUl’)
.childNodes[selected-1]
.classList
.add(‘selected’)
Since you want all the li elements with "selected" and then modify the class of a specific element. A js code like this should work.
//remove the selected class first
document.querySelector("selected").className = "option-item"
//get all li items with class option-item
listOfLi = document.querySelectorAll("li.option-item")
selectedElement = listOfLi.filter(e=>e.data-val==4)//whatever value you want to match it with
selectedElement.className = whatever classes you want to assign.(eg."selected")
I need to add additional styles to only one element of a list depending if the string matches with the url.
In this moment is identifying a unique string form a list and one element in the url, then it compare these two and add the styles depending if the strings are equal, but when doing this is applaying the style to all the elements in the list.
The result should add the styles only to the elements that match the string in the url.
<ul class="__filter--list--categoria" style="display: block;">
<li class="__filter--list--item">
<a class="__anchor" href="/t/cervezas">Cervezas</a>
<ul>
<li class="__filter--list--item">
<a class="__anchor" href="/t/cervezas/nacionales" style="background: red;">Nacionales</a>
</li>
<li class="__filter--list--item">
<a class="__anchor" href="/t/cervezas/internacionales" style="background: red;">Internacionales</a>
</li>
<li class="__filter--list--item">
<a class="__anchor" href="/t/cervezas/artesanales" style="background: red;">Artesanales</a>
</li>
</ul>
</li>
</ul>
var currentUrl = window.location.href.split('/')[5];
var categoryName = $('.__filter--list--categoria .__filter--list--item li .__anchor');
var categoryArray = [];
$(categoryName).each(function() {
categoryArray.push($(this).text())
});
for (x = 0; x < categoryArray.length; x++) {
var categoryString = categoryArray[x].toLowerCase();
if (categoryString === currentUrl) {
console.log('EQUAL...')
$(categoryName).css('background', 'red')
} else {
console.log('NOT EQUAL...')
}
}
You can loop li item by each method, and check href with testurl
let testurl = '/t/cervezas/nacionales';
$('li').each(function(index,item){
let href = $(item).find('a').attr('href');
if(href == testurl){
$(item).css('border', '1px solid green');
}
})
let testurl = '/t/cervezas/nacionales';
$('li').each(function(index,item){
let href = $(item).find('a').attr('href');
if(href == testurl){
$(item).css('border', '1px solid green');
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="__filter--list--categoria" style="display: block;">
<li class="__filter--list--item">
<a class="__anchor" href="/t/cervezas">Cervezas</a>
<ul>
<li class="__filter--list--item">
<a class="__anchor" href="/t/cervezas/nacionales" style="background: red;">Nacionales</a>
</li>
<li class="__filter--list--item">
<a class="__anchor" href="/t/cervezas/internacionales" style="background: red;">Internacionales</a>
</li>
<li class="__filter--list--item">
<a class="__anchor" href="/t/cervezas/artesanales" style="background: red;">Artesanales</a>
</li>
</ul>
</li>
</ul>
Just to explain what is causing the issue, your problem is with this line:
$(categoryName).css('background', 'red')
This is applying the background red to every element that matches the categoryName selector, which is all your anchor tags. You don't currently have a class that uniquely identifies the different url's, see https://stackoverflow.com/a/56634800/264607 for a way to loop through your li elements and apply the style to the correct one
I'm trying to replace two divs that has separate ul elements into a single one, so I can create a single ul with the li of both, but my current code creates separate ul, and that is not my intended purpose, could anyone enlighten me on how to make the proper selection for these:
my jQuery
$('nav div.moduletable_gfbb_navigationbar, nav div.moduletable_menu_navigationbar').replaceWith(function(){
var html = '<ul class="nav navbar-nav navbar-right">';
$(' ul',this).each(function(){
html += $(this).html();
});
html+='</ul>';
return html;
});
my HTML
<div class="moduletable_menu_navigationbar">
<ul class="menu">
<li id="current" class="active item8"><span>Banca Personas</span></li>
<li class="item9"><span>Banca Pyme</span></li>
<li class="item10"><span>Banca Empresas</span></li>
<li class="item602"><span>Bankard</span></li>
</ul>
</div>
<div class="moduletable_gfbb_navigationbar">
<ul class="menu">
<li class="item12"><span>Informacion Institucional</span></li>
</ul>
</div>
And the output I get (not what I want)
<ul class="nav navbar-nav navbar-right">
<li class="item12"><span>Informacion Institucional</span></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li id="current" class="active item8"><span>Banca Personas</span></li>
<li class="item9"><span>Banca Pyme</span></li>
<li class="item10"><span>Banca Empresas</span></li>
<li class="item602"><span>Bankard</span></li>
</ul>
What I want is a single 'ul', I know I can recode it, but I'm trying to use the less code posible.
Your example does not include a <nav> tag which may be the primary cause of your problem, but to produce more readable code I would do it like this.
I used an array for the selectors, because it aids in readability and maintainability. It also allows you to easily insert the new list before the first menu by using only the first selector, whatever that may be.
Basically I select all of the <li> elements descending from the selectors and move those to the newlist. Then insert the new list before the first list div. Then remove the old lists.
var selectors = [
'nav div.moduletable_gfbb_navigationbar',
'nav div.moduletable_menu_navigationbar'
], selectorText = selectors.join(', ');
var newList = $('<ul class="nav navbar-nav navbar-right">');
$('li', selectorText).each(function(){ newList.append(this); });
$(selectors[0]).before(newList);
$(selectorText).remove();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav>
<div class="moduletable_menu_navigationbar">
<ul class="menu">
<li id="current" class="active item8"><span>Banca Personas</span></li>
<li class="item9"><span>Banca Pyme</span></li>
<li class="item10"><span>Banca Empresas</span></li>
<li class="item602"><span>Bankard</span></li>
</ul>
</div>
<div class="moduletable_gfbb_navigationbar">
<ul class="menu">
<li class="item12"><span>Informacion Institucional</span></li>
</ul>
</div>
</nav>
$('.moduletable_menu_navigationbar .menu').append($('.moduletable_gfbb_navigationbar .menu').html());
$('.moduletable_gfbb_navigationbar').remove();
Is this what you are looking for!!