Apply class to parent UL if child LI contains specific class - javascript

I'm currently working on a side menu that will list all pages in the relative section. I pretty much have this sorted apart from 1 small thing. We have 2 levels of dropdowns meaning there are an awful lot of links.
The LI that is active will have the class of .current_page_item. I'm trying to work out a way of saying:
If the UL has a child LI containing .current_page_item class then apply .side_open class to the UL.
$(document).ready(function(){
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li>Demo 1
<ul>
<li class="current_page_item">Demo 11</li>
</ul>
</li>
<li>Demo 2
<ul>
<li>Demo 21</li>
</ul>
</li>
<li>Demo 3
<ul>
<li>Demo 31</li>
</ul>
</li>
<li>Demo 4
<ul>
<li>Demo 41</li>
</ul>
</li>
</ul>
If anyone has any ideas on how this can be done your help would be greatly appreciated!

From what I understand, you want to style the direct parent if the li is selected.
(Comment me if I'm wrong)
So, the following should be what you want to achieve:
(Done with some Javascript)
$(document).ready(function() {
$('ul>li>ul>li').each(function() {
if ($(this).hasClass('current_page_item')) {
$(this).parent().addClass('side_open');
}
});
});
.side_open {
background: #ddd;
}
.current_page_item {
background: #bbb;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li>Demo 1
<ul>
<li class="current_page_item">Demo 11</li>
</ul>
</li>
<li>Demo 2
<ul>
<li>Demo 21</li>
</ul>
</li>
<li>Demo 3
<ul>
<li>Demo 31</li>
</ul>
</li>
<li>Demo 4
<ul>
<li>Demo 41</li>
</ul>
</li>
</ul>

You can use .parentElement property to access li's ul.
const linksArray = [...document.querySelectorAll('li')];
linksArray.forEach(link => {
link.onclick = function() {
linksArray.forEach(link => link.classList.remove('current_page_item'))
this.classList.add('current_page_item')
this.parentElement.classList.add('side_open')
}
})
.current_page_item {
background-color: aliceblue;
}
.side_open:before {
content: 'I have side open class';
}
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
<li>Four</li>
</ul>

You can do it using jquery. It's very simple, using each loop, traverse and check for class in each LI and add .side_open class in it's parent if that li has .current_page_item class.
$(document).ready(function(){
$('ul.main_ul>li>ul.sub_ul>li').each(function(){
if($(this).hasClass('current_page_item')){
$(this).parent().addClass('side_open');
}
});
});
.side_open {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="main_ul">
<li class="main_li">Demo 1
<ul class="sub_ul">
<li class="current_page_item">Demo 11</li>
<li class="current_page_item">Demo 12</li>
</ul>
</li>
<li class="main_li">Demo 2
<ul class="sub_ul">
<li>Demo 21</li>
<li>Demo 22</li>
</ul>
</li>
<li class="main_li">Demo 3
<ul class="sub_ul">
<li>Demo 31</li>
<li>Demo 32</li>
</ul>
</li>
<li class="main_li">Demo 4
<ul class="sub_ul">
<li>Demo 41</li>
<li>Demo 42</li>
</ul>
</li>
</ul>

Related

document.querySelectorAll() only parent items

I have a simple question, I don't know much about JavaScript, how can I get the following documentation as I want
<ul id='mainul'>
<li data-uid='1'>1. item</li>
<li data-uid='2'>2. item
<ul>
<li data-uid="3">
3. item
<ul>
<li></li>
</ul>
</li>
</ul>
<ul>
<li data-uid="4">
4.item
<ul>
<li data-uid="5">5.item</li>
</ul>
</li>
</ul>
</li>
</ul>
I only need to get the 2 ul elements in the #mainul one.
You can use normal scss selecteors to get the node list of thte lis
const listItems = document.querySeectorAll('#mainul > li');
const listItems = document.querySelectorAll('#mainul > li');
console.log(listItems)
<ul id='mainul'>
<li data-uid='1'>1. item</li>
<li data-uid='2'>2. item
<ul>
<li data-uid="3">
3. item
<ul>
<li></li>
</ul>
</li>
</ul>
<ul>
<li data-uid="4">
4.item
<ul>
<li data-uid="5">5.item</li>
</ul>
</li>
</ul>
</li>
</ul>

My sub menu is still not working properly (jQuery)

I'm creating a sub menu using jquery. I have made the code as below. But there is still something that is not working properly. What I want is, when the start, the menu is closed. Currently, all menus are open. How do I do it, can anyone help me?
$('.list-menu > li').click(function () {
var child = $(this).children('ul');
if(child.length===0){
$(this).children().addClass("active");
return;
}
$('.list-menu ul').not(child).slideUp('normal');
child.slideDown('normal');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="list-menu">
<li class="menu-1">
Getting Started
<ul class="submenu">
<li id="sub-1">Child 1
</li>
<li id="sub-2">Child 2
</li>
</ul>
</li>
<li class="menu-2">
Controlling How Data is Indexed
<ul class="submenu">
<li id="sub-3">Child 1
</li>
<li id="sub-4">Child 2
</li>
</ul>
</li>
<li class="menu-3">
Uploading and Indexing Data
<ul class="submenu">
<li id="sub-5">Child 1
</li>
<li id="sub-6">Child 2
</li>
</ul>
</li>
<li>
<a href="#">
Querying For More Information
</a>
</li>
</ul>
You can set the child ul elements to display: none on page load using CSS:
ul > li > ul { display: none; }
$('.list-menu > li').click(function() {
var child = $(this).children('ul');
$(this).children().addClass("active");
$('.list-menu ul').not(child).slideUp('normal');
child.slideToggle('normal');
});
ul > li > ul { display: none; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="list-menu">
<li class="menu-1">
Getting Started
<ul class="submenu">
<li id="sub-1">Child 1
</li>
<li id="sub-2">Child 2
</li>
</ul>
</li>
<li class="menu-2">
Controlling How Data is Indexed
<ul class="submenu">
<li id="sub-3">Child 1
</li>
<li id="sub-4">Child 2
</li>
</ul>
</li>
<li class="menu-3">
Uploading and Indexing Data
<ul class="submenu">
<li id="sub-5">Child 1
</li>
<li id="sub-6">Child 2
</li>
</ul>
</li>
<li>
Querying For More Information
</li>
</ul>

Align items before treeview in ul / li

I have this sample of code:
<ul>
<li>group 1
<ul>
<li>group 1.1</li>
<li> group 1.2</li>
<li>group 1.3
<ul>
<li>group 1.3.1</li>
<li> group 1.3.2</li>
</ul>
</li>
</ul>
</li>
<li>group 2</li>
<li>group 3</li>
</ul>
I want to add some formatted numbers before this treeview all aligned vertically on the left so that the outouput would be something like:
<ul>
<li><span style="margin-left:-30px">10</span>group 1
<ul>
<li><span style="margin-left:-30px">20</span>group 1.1</li>
<li><span style="margin-left:-30px">15</span> group 1.2</li>
<li><span style="margin-left:-30px">07</span>group 1.3
<ul>
<li><span style="margin-left:-30px">100</span>group 1.3.1</li>
<li><span style="margin-left:-30px">08</span> group 1.3.2</li>
</ul>
</li>
</ul>
</li>
<li><span style="margin-left:-30px">90</span>group 2</li>
<li><span style="margin-left:-30px">110</span>group 3</li>
</ul>
I tried adding on the left and align the numbers in those but
that does not work.
Any suggestion ?
Thanks
Here is the solution using CSS. Let me know if this help you out.
.top-level-list {
position: relative;
padding-left: 80px;
}
li>span:first-child {
position: absolute;
left: 0px;
}
<html>
<body>
<ul class="top-level-list">
<li><span>1000.</span>group 1</li>
<ul>
<li><span>20.</span>group 1.1</li>
<li><span>15.</span>group 1.2</li>
<li><span>07.</span>group 1.2</li>
<li><span>102220.</span>group 1.3</li>
<ul>
<li><span>083113.</span>group 1.3.1</li>
<li><span>17.</span>group 1.3.2</li>
</ul>
</ul>
<li><span>90189.</span>group 2</li>
<li><span>110.</span>group 3</li>
</ul>
</body>
</hmtl>
your code looking like your example output...
whats your problem? the look of the points?- this is done in css.
li {
liststyle: disc, circle,......;
}
sorry for missunderstanding in advance.

Nested collapse

I'm trying to collapse a nested menu with jQuery. I read this answer and, to me, it appears to be similar to my solution. The problem is that mine doesn't work.
What I think I'm saying with my JavaScript code is: "hey, when a user clicks on a li that is the parent of a ul.submenu, get its ul.submenu children and attach the slideToggle only to it". But, as you can see from the snippet, it closes also the parent ul.submenu and I can't understand why.
$(document).ready(function () {
$('.submenu').hide();
$('.submenu').parent('li').click(function () {
$(this).children('ul.submenu').slideToggle("slow");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav>
<ul class="menu">
<li>Home</li>
<li>Blog
<ul class="submenu">
<li>
Author
<ul class="submenu">
<li>New</li>
<li>Handle</li>
</ul>
</li>
<li>
<span>Category</span>
<ul class="submenu">
<li>New</li>
<li>Handle</li>
</ul>
</li>
<li>
<span>Tag</span>
<ul class="submenu">
<li>New</li>
<li>Handle</li>
</ul>
</li>
<li>
<span>Post</span>
<ul class="submenu">
<li>New</li>
<li>Handle</li>
</ul>
</li>
</ul>
</li>
<li>Photo</li>
<li>Settings</li>
</ul>
</nav>
You want to stop the click event from bubbling up the DOM and triggering the click handler on the parent. Use .stopPropagation() for that:
$(document).ready(function() {
$('.submenu').hide();
$('.submenu').parent('li').click(function(e) {
e.stopPropagation()
$(this).children('ul.submenu').slideToggle("slow");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav>
<ul class="menu">
<li>Home</li>
<li>Blog
<ul class="submenu">
<li>
Author
<ul class="submenu">
<li>New</li>
<li>Handle</li>
</ul>
</li>
<li>
<span>Category</span>
<ul class="submenu">
<li>New</li>
<li>Handle</li>
</ul>
</li>
<li>
<span>Tag</span>
<ul class="submenu">
<li>New</li>
<li>Handle</li>
</ul>
</li>
<li>
<span>Post</span>
<ul class="submenu">
<li>New</li>
<li>Handle</li>
</ul>
</li>
</ul>
</li>
<li>Photo</li>
<li>Settings</li>
</ul>
</nav>

How to wrap groups of li tags inside ul

I have a navigation menu that contains a bunch of li tags and some of them having this class "sub-item" and I want to group those li tags inside a ul so my navigation which is like this :
<ul class='main-menu'>
<li>Home</li>
<li>Pages</li>
<li class='sub-item'>_Contact Us</li>
<li class='sub-item'>_Community</li>
<li class='sub-item'>_About Me</li>
<li class='sub-item'>_Blog</li>
<li>DropDown </li>
<li class='sub-item'>_Sub Menu 1</li>
<li class='sub-item'>_Sub Menu 2</li>
<li class='sub-item'>_Sub Menu 3</li>
<li class='sub-item'>_Sub Menu 4</li>
<li>Sign Out</li>
</ul>
Will become like this :
<ul id='main-menu'>
<li>Home</li>
<li>Pages</li>
<ul class="sub-menu">
<li class='sub-item'>_Contact Us</li>
<li class='sub-item'>_Community</li>
<li class='sub-item'>_About Me</li>
<li class='sub-item'>_Blog</li>
</ul>
<li>DropDown </li>
<ul class="sub-menu">
<li class='sub-item'>_Sub Menu 1</li>
<li class='sub-item'>_Sub Menu 2</li>
<li class='sub-item'>_Sub Menu 3</li>
<li class='sub-item'>_Sub Menu 4</li>
</ul>
<li>Sign Out</li>
</ul>
This is my attempt to do this but unfortunately it didn't worked :
$('.main-menu li a').each(function() {
var $this = $(this),
content = $this.text();
if (content.indexOf('_') != -1) {
$this.parent('li').addClass('sub-item');
}
});
$('.sub-item').wrapAll('<ul class="sub-menu"></ul>');
Here is a JsFiddle demo : http://jsfiddle.net/hc05fhxr/1/
The desired output given in your question is invalid as li can't have ul as its content.
I possible alternate is to add the new ul as a descendant of the previous anchor
$('li:not(.sub-item)').each(function() {
var $li = $(this),
$subs = $li.nextUntil(':not(.sub-item)');
if ($subs.length) {
$('<ul />', {
'class': 'sub-menu'
}).html($subs).appendTo($li);
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul class='main-menu'>
<li>Home</li>
<li>Pages</li>
<li class='sub-item'>Contact Us</li>
<li class='sub-item'>Community</li>
<li class='sub-item'>About Me</li>
<li class='sub-item'>Blog</li>
<li>DropDown </li>
<li class='sub-item'>Sub Menu 1</li>
<li class='sub-item'>Sub Menu 2</li>
<li class='sub-item'>Sub Menu 3</li>
<li class='sub-item'>Sub Menu 4</li>
<li>Sign Out</li>
</ul>
You should use a combination prev() and after()
$('.main-menu li').each(function(index, el) {
var el = $(el);
if (!el.hasClass("sub-item")) {
el.after($("<ul></ul>"));
} else {
el.prev("ul").append(el);
}
});
$('.main-menu ul:empty').remove()
Here is your fiddle updated:
http://jsfiddle.net/hc05fhxr/3/

Categories