Class descendants disrupting events - javascript

I have a simple drop down menu. When you click .drop-down, a sub menu slides down. However, if you click any of the children of .drop-down, it slides back up again. I want only the .drop-down that was clicked to slide the menu, none of the its descendents.
Here it is in action: http://jsfiddle.net/tmyie/uXn5k/2/
<ul>
<li class="drop-down">
Main
<ul class="sub-menu">
<li>Sub </li>
<li>Sub </li>
<li>Sub </li>
</ul>
</li>
<li>Main </li>
<li>Main </li>
<li>Main </li>
<li>Main </li>
</ul>
jQuery
$( ".drop-down" ).click(function() {
$('.sub-menu').slideToggle();
});
$('.drop-down').fadeTo('slow', 0.3);
http://jsfiddle.net/tmyie/uXn5k/2/

Target the a specifically
$( ".drop-down>a" ).click(function() {
$('.sub-menu').slideToggle();
});
$('.drop-down').fadeTo('slow', 0.3);
Or, just move the class from the li to the a
<ul>
<li>
Main
<ul class="sub-menu">
<li>Sub </li>
<li>Sub </li>
<li>Sub </li>
</ul></li>
<li>Main </li>
<li>Main </li>
<li>Main </li>
<li>Main </li>
</ul>
EDIT:
By the way, you're going to run into trouble with multiple dropdowns using this script. Consider making the following changes:
$( ".drop-down>a" ).on("click", function() {
$(this).siblings('.sub-menu').slideToggle();
});
$('.drop-down').fadeTo('slow', 0.3);
http://jsfiddle.net/uXn5k/6/

Related

Apply class to parent UL if child LI contains specific class

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>

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/

jquery selector first child of ul tag

I have a menu structure like this:
<ul>
<li>One
</li>
<li class="active">Two
<ul>
<li>Sub One
<ul>
<li>Sub One One...</li>
<li>Sub One Two
</li>
</ul>
</li>
<li>Sub Two
<ul>
<li>Sub Two One
</li>
<li>Sub Two Two
</li>
</ul>
</li>
<li>Sub Tree
</li>
</ul>
</li>
<li>Tree
</li>
</ul>
Now... How can i select all sub first "ul" tags in class "active" ?
sample, active > "ul" (sub one) > "ul" (sub one one) ... etc.
You can select like this
JQuery
$('ul li.active>ul')
OR
$('li.active').children('ul')
CSS
ul li.active ul {}
$("li.active").find("ul") will do the trick. Following is the simple code where you can log all the UL elements inside active li.
var ulArr = $("li.active").find("ul");
console.log("First UL of active li is: " + ulArr[0]);
$.each(ulArr, function(index, element) {
console.log("Child UL number " + index + " is: " + element);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>One
</li>
<li class="active">Two
<ul>
<li>Sub One
<ul>
<li>Sub One One...</li>
<li>Sub One Two
</li>
</ul>
</li>
<li>Sub Two
<ul>
<li>Sub Two One
</li>
<li>Sub Two Two
</li>
</ul>
</li>
<li>Sub Tree
</li>
</ul>
</li>
<li>Tree
</li>
</ul>
try
$("li.active >ul:first")
$('.active ul>li>a').first()
$(function() {
var active = $('.active ul>li>a').first().addClass('red');
});
.red {
color:red !important
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<ul>
<li>One
</li>
<li class="active">Two
<ul>
<li>Sub One
<ul>
<li>Sub One One...</li>
<li>Sub One Two
</li>
</ul>
</li>
<li>Sub Two
<ul>
<li>Sub Two One
</li>
<li>Sub Two Two
</li>
</ul>
</li>
<li>Sub Tree
</li>
</ul>
</li>
<li>Tree
</li>
</ul>

JQuery slideToggle for multicolumn list

I`ve got a big list with the width of li 33%, so there are 3 columns.
computers monitors hi-fi
sex-toys pancakes scissors
In each of them there is UL hidden, which on click slideToggle.
JQuery
$('.subCategory > .parentleaf:has(ul) > .categoryicon').click(function() {
$(this).siblings('ul').slideToggle('fast');
});
The problem that dont slide as I want, they rebuld the list every time, like so
computers monitors hi-fi
[li]cars sex-toys pancakes
[li]dogs scissors
I want to slide them this way:
computers monitors hi-fi
[li]cars pancakes scissors
[li]dogs
sex-toys
How can I achieve this??
jsFiddle
jsFiddle 2 - in this case need the red bg color be for 3 columns
I added a clearer div between every three li
<ul class="subCategory">
<li class="parentleaf">
<span class="categoryicon">click</span>
<span class="categoryname">Cars</span>
<ul class="submenu">
<li>Car 1</li>
<li>Car 2</li>
<li>Car 3</li>
<li>Car 4</li>
</ul>
</li>
<li class="parentleaf">
<span class="categoryicon">click</span>
<span class="categoryname">Phones</span>
<ul class="submenu">
<li>Phone 1</li>
<li>Phone 2</li>
<li>Phone 3</li>
<li>Phone 4</li>
</ul>
</li>
<li class="parentleaf">
<span class="categoryicon">click</span>
<span class="categoryname">Guns</span>
<ul class="submenu">
<li>Gun 1</li>
<li>Gun 2</li>
<li>Gun 3</li>
<li>Gun 4</li>
</ul>
</li>
<div class="clearer"></div>
<li class="parentleaf">
<span class="categoryicon">click</span>
<span class="categoryname">Notebooks</span>
<ul class="submenu">
<li>Notebook 1</li>
<li>Notebook 2</li>
<li>Notebook 3</li>
<li>Notebook 4</li>
</ul>
</li>
CSS
.clearer
{
clear:both;
}
You can also get the index of the current clicked li and with some math add a clearer div on click and remove it when needed but there I think there is no need for this

Categories