If list item has child list, add css style - javascript

I have a navigation from a ul, see below:
<nav>
<ul>
<li>Top Link 1</li>
<li>Top Link 2</li>
<ul>
<li><a href="#" >Sub Link 1</a></li>
<li>Sub Link 2</li>
<li>Sub Link 3</li>
</ul>
</li>
<li>Top Link 3</li>
<ul>
<li><a href="#" >Sub Link 1</a></li>
<li>Sub Link 2</li>
<li>Sub Link 3</li>
</ul>
</li>
</ul>
</nav>
I have my css, hiding the the sub link's "ul" unless hovering the parent "li". (Will not show unless asked, as this is not the issues)
I'm trying to use my JQuery to add a css style (margin-bottom:30px;) to the top level "li" only if it has a child "ul" nested in it. My JQuery is as below:
<script>
$(document).ajaxSuccess(function () {
if ($("nav ul >li").children("ul li")) {
$("nav ul >li").hover(function () {
$("nav ul >li").css("margin-bottom", "30");
});
}
});
</script>
This does not appear to be working for me, can anyone point out what I'm doing wrong? Or can they provide a better solution to this approach?

.children will always return an array, check .length
$(document).ajaxSuccess(function () {
if ($("nav ul >li").children("ul li").length > 0) {
$("nav ul >li").hover(function () {
$("nav ul >li").css("margin-bottom", "30");
});
}
});

Try a little something like this :
$('li > ul').each(function(){
$(this).parent().addClass("your class");
});
This will select all uls that are children of li's and apply the class to the respectful li.

you do have an extra </li> in your question which i think is a typo..
<li>Top Link 2</li>
//-------^^^^^here
<ul>
<li><a href="#" >Sub Link 1</a></li>
anyways you check check for length of children if present..
try this
$(document).ajaxSuccess(function () {
if ($("nav ul >li").children().length > 0) {
$("nav ul >li").hover(function () {
$(this).css("margin-bottom", "30");
});
}
});

.children() method returns an object and an object is a truthy value in JavaScript, apart from that if the condition is valuated to true, you are adding a listener to all the li elements not just those that have ul children, You can use .has() method which is a filtering method:
$("nav > ul > li").has('ul').on({
mouseenter: function() {
$(this).css("margin-bottom", "30px");
},
mouseleave: function() {
$(this).css("margin-bottom", "n");
}
});
Or:
li.hovered {
margin-bottom: 30px;
}
$("nav > ul > li").has('ul').on('mouseenter mouseleave', function(e){
$(this).toggleClass('hovered', e.type === 'mouseenter');
});

Related

jQuery or JavaScript menu drop down on click

Right now, I'm trying to build a vertical menu that will have a drop down sub menu below it.
Below is my HTML and the jQuery function I am using:
$(function() {
$('#menusomething > li').click(function(e) {
e.stopPropagation();
var $el = $('ul', this);
$('#menusomething > li > ul').not($el).slideUp();
$el.stop(true, true).slideToggle(400);
});
$('#menusomething > li > ul > li').click(function(e) {
e.stopImmediatePropagation();
});
});
<div id="navmenu">
<ul id="menusomething" style="padding-left:30px">
<li>HOME</li>
<li>ABOUT</li>
<li>CHAPTERS</li>
<ul class="submenu">
<li>Dallas</li>
<li>Los Angeles</li>
<li>New York</li>
<li>Northern California</li>
<li>Orange County</li>
<li>Phoenix</li>
<li>San Diego</li>
<li>Washington DC</li>
</ul>
<li>MEMBER SERVICES</li>
Figured out the answer for anyone who sees this. First had to move the closing li tag from chapters to the end of .submenu Then used this and now it works as wanted.
$(function() {
$('#menusomething li > .submenu').parent().click(function() {
var submenu = $(this).children('.submenu');
if ( $(submenu).is(':hidden') ) {
$(submenu).slideDown(400);
} else {
$(submenu).slideUp(400);
}
});
});
The following code does what I believe you desire: Have a <ul> element that is the nextElementSibling of the first level <li> element slide open and closed when it is clicked. As you mentioned in comments that you desired, it now starts closed due to adding style="display: none;" to the <ul>.
Note: From a user interface perspective, the <li> entries which don't have sub-menus, or are otherwise links, should not have the text enclosed in <a> tags. With the <a> tags the user will think they are clickable, when a click does nothing. This is confusing to a user. It appears that you may have some be sub-menus and some be direct links. If possible, there should be some visual difference between the two types to hint to the user as to what will happen when they click.
Along with other issues, your HTML has nothing that will match either the '#menusomething > li > ul' or the '#menusomething > li > ul > li' selectors. Specifically, you have no <UL> elements that are children of <LI> elements.
$(function() {
$('#menusomething > li').click(function(e) {
e.stopPropagation();
var nextSib = this.nextElementSibling;
if(nextSib && nextSib.nodeName === 'UL') {
//If we get here the nextSib exists and is a <UL> that immediately follows
// the <LI> which was clicked.
$(nextSib).slideToggle(400);
}
});
$('#menusomething > ul > li').click(function(e) {
console.log('Clicked on chapter: ' + this.textContent);
e.stopImmediatePropagation();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id="navmenu">
<ul id="menusomething" style="padding-left:30px">
<li>HOME</li>
<li>ABOUT</li>
<li>CHAPTERS</li>
<ul class="submenu" style="display: none;">
<li>Dallas</li>
<li>Los Angeles</li>
<li>New York</li>
<li>Northern California</li>
<li>Orange County</li>
<li>Phoenix</li>
<li>San Diego</li>
<li>Washington DC</li>
</ul>
<li>MEMBER SERVICES</li>
</ul>
</div>

Event bound to LI is also triggered by clicks on child elements

I got the following structure: - nested UL
<ul class="depth-one">
<li>Category 1
<ul class="depth-two">
<li > Category 1.1</li>
<li> Category 1.2</li>
<li> Category 1.3</li>
</ul>
</li>
<li> Category 2
<ul class="depth-two">
<li>Category 2.1</li>
<li>Category 2.2</li>
<li>Category 2.3</li>
</ul>
</li>
<li>Category 3
<ul class="depth-two">
<li>Category 3.1</li>
<li>Category 3.2</li>
<li>Category 3.3</li>
</ul>
</li>
</ul>
I've applied a rule with CSS:
ul{
list-style: none;
padding:0;
margin:0;
}
.depth-one{
display:block;
}
.depth-two{
display:none;
}
which leaves only the MAIN category shown.
$(document).ready(function() {
$(".depth-one > li").click(function() {
selector = $(this).find(' > .depth-two');
if($(selector).css("display") == "none"){
selector.slideDown(800);
} else {
selector.slideUp(800);
}
});
});
this one, toggles the SUB categories when the MAIN category is being clicked.
here is a fiddle to demonstrate: http://jsfiddle.net/NB4bN/1/
Now, as you can see, when I'm clicking on the SUBCATEGORY, the whole category slides up, any idea why?
I'm trying to achieve that only when I click on the MAIN category, the subcategory will slides up, otherwise, nothing happens when I click on the sub <li> items.
Here is a fix for your problem: http://jsfiddle.net/smerny/NB4bN/2/
$(document).ready(function () {
$(".depth-one > li").click(function (e) {
if (e.currentTarget == e.target) {
selector = $(this).find(' > .depth-two');
if ($(selector).css("display") == "none") {
selector.slideDown(800);
} else {
selector.slideUp(800);
}
}
});
});
I added the check to see if currentTarget and target were the same. So you know if the click is on an element within your li or the li itself.
An easy fix is to stop the event bubbling by adding:
$('li li').click(function (e) {
e.stopPropagation();
});
jsFiddle example
.stoppropagation() prevents an event from bubbling up the DOM tree. So what the above chunk does is look for any list items that are children of other list items and whenever it registers a click on one, it stops the click event from bubbling up the DOM.

Jquery selector: whenever a user clicks on the Category 1/2/3, its `<ul>` will be visible

I got the following structure: - nested UL
<ul>
<li>Category 1
<ul>
<li> Category 1.1</li>
<li> Category 1.2</li>
<li> Category 1.3</li>
</ul>
</li>
<li> Category 2
<ul>
<li>Category 2.1</li>
<li>Category 2.2</li>
<li>Category 2.3</li>
</ul>
</li>
<li>Category 3
<ul>
<li>Category 3.1</li>
<li>Category 3.2</li>
<li>Category 3.3</li>
</ul>
</li>
I've applied a rule with CSS:
ul{
list-style: none;
padding:0;
margin:0;
}
ul ul{
display:none;
}
which leaves only the MAIN category shown.
What i was trying to do is, whenever a user clicks on the Category 1/2/3, its <ul> will be visible. I've tried this code:
$(document).ready(function() {
$("ul li").click(function() {
$(this + "ul").Slidedown(800);
});
});
well, basically I was trying to select the <ul element that was inside the main <ul>.
How do I do it?
Try this.
$(document).ready(function() {
$("ul li").click(function() {
$(this).find('ul').Slidedown(800);
});
});
Given your selector, click on Category 1.1 will also call the callback, but it won't do anything since it doesn't have any ul tags. Still, it's better to add a class and bind the event only on those.
this is not a string, it's a DOM element.
Instead of $(this + "ul"), you want $('ul', this).
P.S. .Slidedown should be .slideDown.
$(this).find('ul:hidden').slideDown(800);
something like this should work
$(document).ready(function() {
$("ul > li").click(function() {
$(this).find("> ul").Slidedown(800);
});
});
Although, an even more efficient approach(thanks to Ian) would be:
$(document).ready(function() {
$("ul").children('li').click(function() {
$(this).children("ul").Slidedown(800);
});
});
using the '>' operator tells jquery to only look for direct children, if you don't use '>' the code will apply to the li elements inside the nested ul as well. also, read the other answers info about using 'this' properly.
You're concatenating the DOM element with "ul" to a string - that's not a valid selector. Instead, use .find() to apply the ul selector in the context of the current element.
$(document).ready(function() {
$("ul li").click(function() {
$(this).find('ul').Slidedown(800);
});
});
And maybe make the ul li selector a bit more specific to match only the outer list items.

jQuery show submenu if parent have been clicked

Could some one please help with code.
I want to show the submenu only when submenu parent is clicked.
HTML
<ul>
<li>Item</li>
<li>Item
<ul class="sub-menu">
<li>Submenu</li>
<li>Submenu</li>
</ul>
</li>
<li>Item</li>
<li>Item
<ul class="sub-menu">
<li>Submenu</li>
<li>Submenu</li>
</ul>
</li>
<li>Item</li>
</ul>
So if you click on the parent submenu will show.
Here is fiddle link - http://jsfiddle.net/KhNCV/1/
$('.sub-menu').hide();
$("li:has(ul)").click(function(){
$("ul",this).slideDown();
});
http://jsfiddle.net/3nigma/KhNCV/2/
OR
$('.sub-menu').hide();
$("li:has(ul)").click(function(){
$("ul",this).toggle('slow');
});
http://jsfiddle.net/3nigma/KhNCV/4/
Here's your example working. It's unclear why you need the a tags, as you could use cursor: pointer in the CSS to make the li appear clickable. I'll assume you want to do some spiffy hovering on them in IE that's CSS only? If not, you could simplify by removing them.
Instead of doing hide() on .submenu, you should use CSS (parsed with DOM instead of onReady/load).
.sub-menu { display: none; }
And then here's you code to toggle the menus:
$('ul li a').click(function() {
$(this).parent().find('ul.sub-menu').toggle();
return false;
});
$('.sub-menu').hide();
$("a").click(function(){
$(this).parent().children("ul").toggle();
})
check out this link
http://jsfiddle.net/KhNCV/6/
$('li a').click(
function() {
$(this).next().slideToggle();
})
Try this
$(function(){
//Hide all the sub menus
$('.sub-menu').hide();
$("li:has(ul)").click(function(){
//Find the child ul and slideToggle
$(this).children("ul").slideToggle();
});
});

jQuery detect child <ul>

HTML:
<ul class="menu">
<li>Text
<ul>
<li>Text
<li>Text
<li>Text
</ul>
</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text
<ul>
<li>Text
<li>Text
<li>Text
</ul>
</li>
<li>Text</li>
</ul>
JS:
$(".menu li a").click(function() {
$(this).parent().find("ul").toggle();
return false;
});
How to make this js work only when <li> has <ul> inside it?
Without adding extra classes.
It should not work when there is no child <ul> inside current <li>.
Example of this available on jsfiddle.net
Its better if you give link to your working example.
Try restricting the parent to bring back the first li, right now it is finding the ul of an li as the top level container then has within it several other ul so the logic is working as written.
$(".menu li a").click(function() {
return !($(this).parents("li:first").find("ul").toggle().length)
});
To perform an action if there's a child ul of the currently-hovered li:
$('li').hover(
function(){
if ($(this).has('ul')) {
// do stuff
}
});
I was going to add that you could also just use the :has selector with a parent > child selector (demo):
$('.menu li:has(ul) > a').click(function() {
$(this).parent().find('ul').toggle();
return false;
});

Categories