How to properly structure lists with many sub-levels - javascript

I have a large navigation menu made using li and ul tags. The problem I have is that if I try to style individual items, it becomes very challenging because each li tag has multiple ul and li elements within it and therefore the style gets applied to everything within it. For example, I'm trying to highlight the first list item "SharePoint Demo Website" but that first item contains all the other items, it's an expandable/collapsible menu).
HTML:
<ul id="expList" class="list">
<li title="Sharepoint Demo Website" value="https://demo.ca" class="collapsed expanded active">Sharepoint Demo Website
<ul style="display: block;">
<li title="Academic" value="https://demo.ca/academic" class="collapsed">Academic
<ul style="display: none;">
<li title="Board Meetings" value="https://demo.ca/academic/bm">Board Meetings</li>
<li title="Committee" value="https://demo.ca/academic/cmtte">Committee</li>
<li title="Document Management" value="https://demo.ca/academic/dm">Document Management</li>
<li title="Project Management" value="https://demo.ca/academic/pm">Project Management</li>
</ul>
</li>
<li title="Archive" value="https://demo.ca/archive">Archive</li>
<li title="Associations" value="https://demo.ca/associations" class="collapsed">Associations
<ul style="display: none;">
<li title="Board Meetings" value="https://demo.ca/associations/bm">Board Meetings</li>
<li title="Document Management" value="https://demo.ca/associations/dm">Document Management</li>
<li title="Project Management" value="https://demo.ca/associations/pm">Project Management</li>
</ul>
</li>
<li title="Developer" value="https://demo.ca/cdn">Developer</li>
<li title="Person test" value="https://demo.ca/cf_test">Person test</li>
<li title="Charity" value="https://demo.ca/charity" class="collapsed">Charity
<ul style="display: none;">
<li title="Board of Directors" value="https://demo.ca/charity/bod" class="collapsed">Board of Directors
<ul style="display: none;"><li title="Board Documents" value="https://demo.ca/charity/bod/boarddocs">Board Documents</li>
<li title="Meeting Materials" value="https://demo.ca/charity/bod/mtgmaterial">Meeting Materials</li>
</ul>
</li>
</ul>
</li>
<li title="demo" value="https://demo.ca/clite" class="collapsed">demo
<ul style="display: none;"><li title="administrator" value="https://demo.ca/clite/admin">administrator
</li>
</ul>
</li>
<li title="Company" value="https://demo.ca/company" class="collapsed">Company
<ul style="display: none;"><li title="Finance" value="https://demo.ca/company/finance">Finance</li>
<li title="Human Resources" value="https://demo.ca/company/hr" class="collapsed">Human Resources
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
CSS:
#expList ul li:hover{
background-color: #eee;
}
This is what it looks like:
This is the code that creates the list:
function traverseMap(obj, element) {
for (var key in obj) {
var item = obj[key];
var li = $('<li>', {
text: item.title,
title: item.title,
value: item.url
}).appendTo(element);
if (!$.isEmptyObject(item.children)) {
var ul = $('<ul>').appendTo(li);
traverseMap(item.children, ul);
}
}
}
traverseMap(map, $('#expList'));
}

You can use > to affect only immediate children, like this:
#expList ul > li:hover{
background-color: #eee;
}
or this:
#expList > ul > li:hover{
background-color: #eee;
}
or use the :first-child pseudo selector for just the first child:
#expList ul li:first-child:hover
{
background-color:yellow;
}
depending on what you want. You could also use class names.

The way you have right now it won't work, because the whole node will get highlighted, what you need to do is to give an extra mark up to the text you wanna highlight, for example :
<li title="Academic" value="https://demo.ca/academic" class="collapsed">
<span>Academic</span>
<ul style="display: none;">
<li title="Board Meetings" value="https://demo.ca/academic/bm">Board Meetings</li>
<li title="Committee" value="https://demo.ca/academic/cmtte">Committee</li>
<li title="Document Management" value="https://demo.ca/academic/dm">Document Management</li>
<li title="Project Management" value="https://demo.ca/academic/pm">Project Management</li>
</ul>
</li>
then :
#expList ul > li:hover > span{
background-color: #eee;
}

Given that <li title="Sharepoint Demo Website" value="https://demo.ca" class="collapsed expanded active"> contains a text node and children elements, a rule that styles the li will also apply to its children.
If you want to style the text node ("Sharepoint Demo Website") independently you will have to wrap it in an element which you can target specifically.
<ul id="expList" class="list">
<li title="Sharepoint Demo Website" value="https://demo.ca" class="collapsed expanded active">
<span>Sharepoint Demo Website</span>
<ul style="display: block;">
<li title="Academic" value="https://demo.ca/academic" class="collapsed">Academic
<ul style="display: none;">
You could now apply a rule to the text node via the span
#expList li > span {
background-color:#fee;
}
See jsfiddle.

Related

How to change parent category color and child category color in product category widget

how to highlight the category of the selected parent category without highlighting the child categorys? i tried many stuff and not able to solve it.
My css now looks like :
.widget .children .current-cat {
background-color: beige;
}
PS: HTML WooCommerce Widget:
<div id="woocommerce_product_categories-2" class="widget woocommerce widget_product_categories" style="padding: 15px;border-width: 1px;border-style: solid;border-color: rgba(9,12,15,0.28);">
<ul class="product-categories">
<li class="cat-item cat-item-39 cat-parent current-cat-parent">Videoüberwachung
<ul class="children">
<li class="cat-item cat-item-43 current-cat">HDCVI Kameras</li>
<li class="cat-item cat-item-44">IP-Netzwerk Kameras</li>
</ul>
</li>
</ul></div>
.sidebar-widget .product-categories .cat-item a{color: red;}
.sidebar-widget .product-categories .cat-item .children a{color: yellow;}

How to hide li if ul has no have li with class using jquery or javascript

Im trying to hide li if has no have li
Here html :
<li>
My Profile
<ul>
<li>Profile</li>
<li>Edit Profile</li>
</ul>
</li>
<li>
Menu must be hide
<ul>
</ul>
</li>
Get all the ul iterate through them to get the content and if no conetent is available then use parentNode to get the parent li and add class to the parent to hide it
const allULs = document.querySelectorAll("ul");
allULs.forEach(function(a) {
0 === a.innerHTML.trim().length &&
a.parentElement.classList.add("hideParent");
});
.hideParent {
display: none;
}
<li>
My Profile
<ul>
<li>Profile</li>
<li>Edit Profile</li>
</ul>
</li>
<li>
Menu must be hide
<ul>
</ul>
</li>

jQuery toggle text color from self and removing from others

I'm new to jQuery/js, and I'm trying to toggle colors on click with jQuery.
I need something like this:
When I click an item, it toggles a class to change color.
If I click an item once, it changes color. Then if I click another item it changes color, but the other items must return to their initial color.
I can manage to toggle each item color, but I'm unable to remove the class color from the others.
Only the <li> with the class submenu-toggler should change colors. The 2nd level ul should not have their lis changed.
The final code looks something like this:
$(".submenu-toggler a").click(function(){
$(this).siblings().removeClass('red');
$(this).toggleClass("red");
});
a {
color: gray;
}
.red {
color: red;
}
li {
list-style-type: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="main-nav-menu" class="menu-hide">
<li>Item1</li>
<li class="submenu-toggler">
Toggler<span></span>
<ul id="submenu-1" class="main-nav-submenu">
<li>sub1</li>
<li>sub2</li>
<li>sub3</li>
<li>sub4</li>
</ul>
</li>
<li>Item3</li>
<li>Item4</li>
<li class="submenu-toggler">
Toggler<span></span>
<ul id="submenu-2" class="main-nav-submenu">
<li>sub1</li>
<li>sub2</li>
<li>sub3</li>
</ul>
</li>
<li>Item6</li>
</ul>
I believe this is what you are looking for, by using .siblings() all what you have to do is to remove class .red from the siblings elements and then perform the toggle on the current clicked element
Update: its working now for other elements, note that I added a selector .red * to make sub-elements also colored in red:
$(".item").click(function(){
$(this).siblings().removeClass('red');
$(this).toggleClass("red");
});
li {
color: grey;
}
.red,
.red *{
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li class="item"><a>Item 1</a></li>
<li class="item"><a>Item 2</a></li>
<li class="item">
<a>Item 3</a>
<span>AA</span>
<ul>
<li>AA</li>
<li>AA</li>
</ul>
</li>
</ul>
<ul id="main-nav-menu" class="menu-hide">
<li class="item">Item1</li>
<li class="item submenu-toggler">
Toggler<span></span>
<ul id="submenu-1" class="main-nav-submenu">
<li>sub1</li>
<li>sub2</li>
<li>sub3</li>
<li>sub4</li>
</ul>
</li>
<li class="item">Item3</li>
<li class="item">Item4</li>
<li class="item submenu-toggler">
Toggler<span></span>
<ul id="submenu-2" class="main-nav-submenu">
<li>sub1</li>
<li>sub2</li>
<li>sub3</li>
</ul>
</li>
<li class="item">Item6</li>
</ul>

removing html tags but keep the inner html

I have a nav menu which have a mega menu.It has several markup to make it a mega menu.But i want to remove some of the markups when in small viewport.
So my markups are
<ul class="megamenu-wrapper">
<li>
<ul>
<li>Home</li>
<li>Abort</li>
<li>Contact</li>
</ul>
</li>
<li>
<ul>
<li>gang</li>
<li>menu</li>
<li>food</li>
</ul>
</li>
</ul>
what i want
<ul class="megamenu-wrapper">
<li>Home</li>
<li>Abort</li>
<li>Contact</li>
<li>gang</li>
<li>menu</li>
<li>food</li>
</ul>
i have two mega-menu-wrapper
What i have tried
var megaContents = $('.megamenu-wrapper li ul').contents();
$('.megamenu-wrapper li ul').replaceWith( megaContents );
It makes a same list in two each mega menu and in each megamenu there is about 5 times repetation of each elements.
Anyone please help.
Use
//Fimd child ul li and append it to main ul
$('.megamenu-wrapper > li > ul > li').appendTo('.megamenu-wrapper');
//Remove li having ul
$('.megamenu-wrapper > li:has(ul)').remove();;
$(document).ready(function() {
$('.megamenu-wrapper > li > ul > li').appendTo('.megamenu-wrapper'); +
$('.megamenu-wrapper > li:has(ul)').remove();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="megamenu-wrapper">
<li>
<ul>
<li>Home
</li>
<li>Abort
</li>
<li>Contact
</li>
</ul>
</li>
<li>
<ul>
<li>gang
</li>
<li>menu
</li>
<li>food
</li>
</ul>
</li>
</ul>
use .each() if you have multiple menus
$('.megamenu-wrapper') each(function () {
$(this).find('> li > ul > li').appendTo(this);
$(this).find(' > li:has(ul)').remove();
});
DEMO
With your current markup, you can use append() which will take the children li with anchors and append them as direct children of .megamenu-wrapper
Then, use remove() to remove the former parent li elements which now contain empty ul children
$('.megamenu-wrapper').append($('li:has(a)'));
$('.megamenu-wrapper').children('li:has(ul)').remove();
Update
For multiple menus, you can use the snippet above, but wrap it in an each() call
$('.megamenu-wrapper').each(function(){
$(this).append($(this).find('li:has(a)'));
$(this).children('li:has(ul)').remove();
});
$('.megamenu-wrapper').each(function(){
$(this).append($(this).find('li:has(a)'));
$(this).children('li:has(ul)').remove();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<ul class="megamenu-wrapper">
<li>
<ul>
<li>Home</li>
<li>Abort</li>
<li>Contact</li>
</ul>
</li>
<li>
<ul>
<li>gang</li>
<li>menu</li>
<li>food</li>
</ul>
</li>
</ul>
<ul class="megamenu-wrapper">
<li>
<ul>
<li>Home</li>
<li>Abort</li>
<li>Contact</li>
</ul>
</li>
<li>
<ul>
<li>gang</li>
<li>menu</li>
<li>food</li>
</ul>
</li>
</ul>

How to add on click a li element to another container and rest of li stay fixed

I have a litle problem:
I have this list:
<ul id="nextlevel">
<li class="listadetalii"><a style="width:100%;color:red;font-weight:600;cursor:pointer" rel="03.Accessories" data-folder="01.Hi tech (028_003)" data-titlu="Hi tech" id="01.Cosuri si cuiere" class="red-gros singlelink folder">Hi tech<p style="width:100%;color:#828282;font-size:70%" class="muted">Luni, 18 Mar 2013 16:07:14</p></a>
<ul class="detalii-produs hide">
<li class="togo">Image 1</li>
<li class="detalii-produs-lista dropdown-submenu">Fișă produs
</li>
<li class="detalii-produs-lista dropdown-submenu">Listă prețuri
</li>
</ul>
</li>
<li class="listadetalii"><a style="width:100%;color:red;font-weight:600;cursor:pointer" rel="03.Accessories" data-folder="02.Net (028_002)" data-titlu="Net" id="01.Cosuri si cuiere" class="red-gros singlelink folder">Net<p style="width:100%;color:#828282;font-size:70%" class="muted">Marti, 16 Apr 2013 09:53:43</p></a>
<ul class="detalii-produs hide">
<li class="togo">Image 2</li>
<li class="detalii-produs-lista dropdown-submenu">Fișă produs
</li>
<li class="detalii-produs-lista dropdown-submenu">Listă prețuri
</li>
</ul>
</li>
<li class="listadetalii "><a style="width: 100%; color: red; font-weight: 600; cursor: pointer; outline: medium none;" rel="03.Accessories" data-folder="03.)" data-titlu="Cuiere" id="01.Cosuri si cuiere" class="red-gros singlelink folder">Cuiere<p style="width:100%;color:#828282;font-size:70%" class="muted">Luni, 18 Mar 2013 10:53:47</p></a>
<ul class="detalii-produs hide" style="display: none;">
<li class="togo">Image 3</li>
<li class="detalii-produs-lista dropdown-submenu">Fișă produs
</li>
<li class="detalii-produs-lista dropdown-submenu">Listă prețuri
</li>
</ul>
</li>
This list is collapsed. When i click on "Hi tech" a next list is expanded and the content is visible.
I want the content of the li element class togo to go on div alfa and hide li and the rest of li-s stay on this list.
Same behavior for the rest of elements Net, Cuiere...
<div id="alfa">here must be Image (n)</div>
More detalied code on fiddle http://jsfiddle.net/gxg1974/Jy3EK/
Thank you all for tips and guidance.
For what i understand is, you want the content of togo to be in div#alfa. So here's how to do it..
$('ul#nextlevel a.singlelink').on("click", function () {
$(this).css('outline', 'none');
if ($(this).parent().hasClass('current')) {
$(this).siblings('ul').slideUp('slow', function () {
$(this).parent().removeClass('current');
});
} else {
var img = $(this).siblings('ul').children("li.togo").hide()
.html();
console.log(img);
$("#alfa").html(img);
$('ul#nextlevel li.current ul').slideUp('slow', function () {
$(this).parent().removeClass('current');
});
$(this).siblings('ul').slideToggle('slow', function () {
$(this).parent().toggleClass('current');
});
}
return false;
});
DEMO FIDDLE
UPDATE
I've used .on instead of live as .live() is deprecated.
If there's something more, let me know.

Categories

Resources