I have ul list in which there are some li which having nested li as well.
I have added js in which onclick of li, its change bgcolor of li,but issue is its spreading to nested li as well.
my code is :
< ul >
< li >
< a > first </ a>
/%nested ul starts here%/
<li>
Nested Word
</li>
</li>
</ul>
JAVASCRIPT:
$('li').click(function(e){
$(this).addClass("active1");
$(this).find('a').addClass("acolor");
});
CSS
.acolor
{
color: #FFFFFF !important;
}
.active1
{
background-color:#536574 !important;
}
Issues is when I am applying bg color to main div, its appying to near by padding of nesed li as well, which I dont need. I need just bg color to apply first text and not anywhere to its children.
-> I cant change HTML structure as its already code coming from Drupal widget.
Is there any solution ?
Thanks !!
The $('li') jQuery statement selects every <li> in your DOM, including the ones you don't want to select. If you just want to change the background color of your text elements (<a> tags) you could rewrite the statement like this:
$('a').click(function(e){
$(this).addClass("active1");
$(this).find('a').addClass("acolor");
});
Or if you wanted to selecxt just the first <li> inside your <ul>, select them like this:
$('ul li:first-child').click(function(e){
$(this).addClass("active1");
$(this).find('a').addClass("acolor");
});
if you just want to select the a tag directly under the clicked li just use the child selector ">" which would result in the following javascript:
$('li').click(function(e){
$(this).addClass("active1");
$(this).find('> a').addClass("acolor");
});
Related
I have a menu where I would like a sub-menu to appear as long as the user is in that menu; Much like you would find in a mega-menu.
I'm using jQuery to select the elements.
This is the markup structure:
As you can see each <li> i.e. global-nav__list-item contains an anchor which represents an element in the main navigation.
Also nested in there is the corresponding div element i.e. collapsible__content which represents the mega-menu.
I thought this script could drill down and simply add and remove the class collapsible__content--expanded on collapsible__content which would solve my problem.
$('.global-nav__list-item').mousemove(function() {
$(this > '.collapsible > .collapsible_content').addClass('collapsible__content--expanded');
}, function(){
$(this > '.collapsible > .collapsible_content').removeClass('collapsible__content--expanded');
})
What am I doing wrong?
Firstly, your selector isn't valid. You need to use find() when attempting to select child elements from the this reference: $(this).find('.collapsible > .collapsible_content').
Secondly, mousemove() doesn't accept multiple functions. Assuming you're expecting to add/remove the class on mouseenter/mouseleave you could use hover instead, along with toggleClass():
$('.global-nav__list-item').hover(function() {
$(this).find('.collapsible > .collapsible_content').toggleClass('collapsible__content--expanded');
});
Better still, you could use CSS alone to achieve this:
.global-nav__list-item .collapsible > .collapsible-content {
display: none;
}
.global-nav__list-item:hover .collapsible > .collapsible-content {
display: block;
}
The above is assuming the .collapsible__content--expanded is just hiding/showing content. If not, you'd simply need to copy the relevant styles in to the above.
Try this:
$('.global-nav__list-item').mouseover(function() {
$(this).find('.collapsible > .collapsible_content').addClass('collapsible__content--expanded');
});
$('.global-nav__list-item').mouseout(function(){
$(this).find('.collapsible > .collapsible_content').removeClass('collapsible__content--expanded');
})
I am trying to show which menu item is the active one when it's clicked on by reassigning a css class to the list item using jQuery. I've looked at some examples online and tried some different ones, but I can't seem to get mine to work at all. Can someone look at my code from my last try and tell me what I am doing wrong? Thanks for your help.
Script in HEAD tag:
<script type="text/javascript" src="script/jquery-1.11.2.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$("#topnavi ul li a").click(function () {
if ($(this).parent("li").hasClass(".select"))
$("#topnavi ul li a").parent("li").removeClass(".select").addClass(".norm");
$(this).parent("li").removeClass(".norm").addClass(".select");
});
});
</script>
HTML:
<div id="topnavi">
<ul>
<li class="select">HOME</li>
<li class="norm">ABOUT US</li>
<li class="norm">SERVICES</li>
<li class="norm">PACKAGES</li>
<li class="norm">COMMENTS</li>
<li class="norm">CONTACT US</li>
<asp:LoginView ID="lvBackgroundSound1" runat="server">
<RoleGroups>
<asp:RoleGroup Roles="administrator"><ContentTemplate><li class="norm">ADMIN</li></ContentTemplate></asp:RoleGroup>
</RoleGroups>
</asp:LoginView>
</ul>
</div>
When a new anchor in a list item is clicked on, I would like to assign the "norm" class to the list item surrounding the previously selected anchor and assign the "select" class to the list item surrounding the newly selected anchor.
You don't need the dot before the class name when using hasClass, addClass and removeClass.
Change
if ($(this).parent("li").hasClass(".select"))
$("#topnavi ul li a").parent("li").removeClass(".select").addClass(".norm");
$(this).parent("li").removeClass(".norm").addClass(".select");
to
if ($(this).parent("li").hasClass("select"))
$("#topnavi ul li a").parent("li").removeClass("select").addClass("norm");
$(this).parent("li").removeClass("norm").addClass("select");
In conjunction with Tobias' answer, you might want to add some opening brackets to this part of the code
if ($(this).parent("li").hasClass(".select")) {
$("#topnavi ul li a").parent("li").removeClass(".select").addClass(".norm");
$(this).parent("li").removeClass(".norm").addClass(".select");
}
Or something along those lines. You could also use .toggleClass() instead of removing and adding the classes.
Adding to what Tobias already mentioned, change
if ($(this).parent("li").hasClass(".select"))
$("#topnavi ul li a").parent("li").removeClass(".select").addClass(".norm");
$(this).parent("li").removeClass(".norm").addClass(".select");
To
$("#topnavi ul li").removeClass("select").addClass("norm");
$(this).parent("li").removeClass("norm").addClass("select");
This will make sure select class is assigned only to the selected li and rest other li elements will have norm class.
I have the following code, which works perfectly, except when it comes to nested LI elements that might be nested under the li element I am targeting:
$('#comment-section .comment-box a#un-do').hide();
$('#comment-section ul li[data-is-archived="true"]').map(function() {
$('#comment-section ul li[data-is-archived="true"]').css('text-decoration', 'line-through');
$('#comment-section ul li[data-is-archived="true"] a#un-do').show();
}).get();
What this will do is strike out any text in this li element, and show the undo link for each li element that matches this particular element (or set of).
ul
li - strike through works, shows undo button, data-is-archived = true
ul
li - strike through works, shows undo button, data-is-archived = false
Why is every nested li element getting striked through and having a link appear when only the ones with data-is-archived=true should have the strike through and the link show up - as code states?
That is because the text-decoration: strike-through property applies to all text in the <li> element that has the HTML5 data attribute is-archived of the value true, regardless of whether the nested children fits the selector or not. I have replicated your problem in a JSfiddle (please do that yourself next time): http://jsfiddle.net/teddyrised/TZVej/1/
The solution would be to wrap the text within each <li> element with a <span> element, and apply that via restrictive, direct descendent-only CSS.
$('#comment-section .comment-box a#un-do').hide();
$('#comment-section ul li[data-is-archived="true"]').map(function() {
// Target only <span> elements that are direct descendants
$('#comment-section ul li[data-is-archived="true"] > span').css('text-decoration', 'line-through');
$('#comment-section ul li[data-is-archived="true"] a#un-do').show();
}).get();
See proof-of-concept fiddle here: http://jsfiddle.net/teddyrised/TZVej/2/
p/s: I am not sure why you are using the .map() function when there is no use for it in the question's context...
Here's an example of what I'm aiming for:
I don't like I have to decorate a li element with a class in order to correctly fire the event. What happens if I have more than one nested category drop down? Things get messy quick!
I also can't seem to be able to select an option without it closing as soon as I leave the event capture area.
Any suggestions on how to build a well crafted, drop down navigation menu?
You don't really need any classes with some clever usage of the selectors :P
I set up a fiddle with an example, here's the code:
HTML:
<nav>
<ul>
<li>HOME</li>
<li>
OFFERS
<ul>
<li>
NEW
<ul>
<li>YAY!</li>
</ul>
</li>
</ul>
</li>
<li>SETTINGS</li>
<li>TV's</li>
<li>COMPUTERS</li>
<li>RICE</li>
</ul>
</nav>
As you see, not a single class/id was needed :P The element "OFFERS" is the only one with a drop-down menu, and inside that menu, the element "NEW" has another one.
CSS:
li > ul { display: none; }
li li { margin-left: 10px; }
The first style is the important one. At first, we want our submenus to be hidden. The other style is just for the sake of clarity.
jQuery:
$("nav ul li").hover(function(){
if ($("> ul", this).length > 0) {
$("> ul", this).show();
}
}, function(){
if ($("> ul", this).length > 0) {
$("> ul", this).hide();
}
});
Yup, as simple as that :) When we hover a menu element, we check if it has any ul direct children, if it does, we show them. When we leave the menu element, we check again if it has any ul direct children, and if it does, we hide them.
Of course, you'll need to style this up, and make sure your clear any float inside any li.
You would need to use classes to properly control the flow. Especially on your outer container.
For example in my menus i have a ul containing all the menu and each menu item is an li. Inside the li is the first level title, along with another ul containing the submenu.
<ul class="menu">
<li>
Item 1
<ul><!--Further items--></ul>
</li>
<li>
Item 2
<ul><!--Further items--></ul>
</li>
</ul>
You can then control this using child selectors. Although it is sometimes easier to simply use a class.
$(".menu > li") //First level items
$(".menu > li > ul") //Submenus
Say you wanted to make the menu slide down when you clicked on one of the first level items:
$(".menu > li").click(function() {
$this = $(this); //Caching. Not really needed for this example. But anyway :)
$this.children("ul").slideToggle("fast");
});
$(document).ready( function(){
$("ul.MenuNavi li").mouseover(function(){
$(this).children('ul').slideDown('3000');
});
$("ul.MenuNavi li").mouseleave(function(){
$(this).children('ul').stop(true).slideUp('3000');
});
});
I was making a menu today, and I stumbled on this curious case, with the following HTML:
<div id="list1">
<ul>
<li>1</li>
<li>2 - Here is a Submenu
<ul>
<li>3</li>
<li>4</li>
</ul>
</li>
</ul>
</div>
Then i used the following js:
$('#list1 li').click(function(){
$('.list-item').removeClass('list-item');
$(this).addClass('list-item');
});
When I do this the class would only be applied to the outer <li>, but I wanted it to be applied to both the parent and child LIs.
Now my question is, how can I handle this "returns" so I apply the classes to both the parent and child LIs?
How does js handle these type of selectors? Is the event really running twice and removing the last class that was set?
The issue is that $('#list1 li') can select both levels of li tags inside #list and apply a click handler to both. In addition, you are allowing the click to propagate up so it may be seen by more than just the one you click on.
If you only want the outer level, then you should use direct child specifications like this. and that will isolate what click handler is actually installed:
$("#list > ul > li")
This will only get the top level li tags. And, the whole code would look like this:
$('#list1 > ul > li').click(function(){
$('.list-item').removeClass('list-item');
$(this).addClass('list-item');
});
If you want to isolate the removeClass operation to just the other LI tags at the same level, not across the entire document, then you can use something like this:
$('#list1 > ul > li').click(function(){
$(this).addClass('list-item').siblings().removeClass('list-item');
});
Your comments have me a bit confused about this LI tags you want clickable. If you actually want the lower level to be clickable and then apply the list-item class to both the one that was clicked and the parent LI, then you can do that like this:
$('#list1 > ul > li > ul > li').click(function() {
$("#list1 .list-item").removeClass('list-item');
$(this).parents("li").add(this).addClass('list-item');
return(false); // stop event propagation
});
Whether or not jQuery applies a method to one element in a list of elements or all of them depends on the method.
.click() and .addClass() will both be applied to all jQuery objects in your selector.
In your case, a click handler is applied to all li elements in #list. $(this) applies to the specific li that was clicked on.
However, you have nested li elements, which means that multiple click handlers fire when you click on an inner nested li, both the nested li and it's parent li.
To prevent this event propagation through the dom tree, put a stopPropagation() call in your click handler:
$('#list1 li').click(function(e){
e.stopPropagation();
$('.list-item').removeClass('list-item');
$(this).addClass('list-item');
});
You can also return false from your handler, which stops propagation and prevents default actions. This is specific to jQuery.
if you are adding a "current" page style:
$('#list1 > ul > li').on('click',function(){
$(this).addClass('list-item') //adds class to clicked item
.siblings() //find the others of the same level
.removeClass('list-item'); //remove their styles
});