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');
});
});
Related
I'm simply creating a nav menu and have a basic unordered list with a "sub-menu" within. Here's the Jquery. The reason for the "active" class and if statement is that I want the slider to remain open if choosing another item on the list, so that it doesn't close and open again each iteration.
The problem part here for me in the code is here.
$('.slider').html( $(this).find('ul') );
The main issue is that on('click',), is only updating the first time it's clicked. On a second click on another item in the menu, it doesn't update itself with the new selection and therefore doesn't show the new sub-menu list? Console log shows that it is undefined. But it should be like the first time?
I don't understand why this is happening or the reasons behind it! Logic tells me the same thing that happens the first time, should keep happening, and therefore work?! Help appreciated before I make a hole in the wall with me forehead!
$(document).ready(function() {
$('ul > li > ul').hide();
$('.slider').hide();
// Menu
$('.menuNav > ul > li').on('click', function() {
// if active
if ( $(this).hasClass('active') ) {
$(this).parents().children().removeClass('active');
$('.slider').hide('slide', 200);
}
// if unactive
else {
$(this).addClass('active');
$('.slider').show('slide', 200);
$(this).siblings().removeClass('active');
// Show related list
$('.slider').html( $(this).find('ul') );
}
});
});
HTML
<div class="menuNav">
<ul>
<li><span>item_1</span>
<div class="sub_position">
<ul>
<li>sub-item_1-1</li>
<li>sub-item_1-2</li>
<li>sub-item_1-3</li>
<li>sub-item_1-4</li>
</ul>
</div>
</li>
<li><span>item_2</span>
<div class="sub_position">
<ul>
<li>sub-item_2-1</li>
<li>sub-item_2-2</li>
<li>sub-item_2-3</li>
<li>sub-item_2-4</li>
</ul>
</div>
</li>
.... etc
</ul>
</div>
Your issue likely arises from the fact that you are actually moving the entire submenu into .slider, instead of cloning it. This means that the submenu will be removed from the original menu the first time you click it, and clicking on it again will mean that the nested submenu selector $(this).find('ul') will return an empty set.
To circumvent this issue, I suggest that you do the following:
Append the outerHTML of the submenu to slider, i.e. $(this).find('ul')[0].outerHTML
If you want to hide the submenu in the menu when this is done, simply hide/unhide it when appropriate.
You can always use $(this).find('ul').html() for the same effect, but remember that <li> elements must be immediate children of <ul>. Therefore, we need to clone the outerHTML as well (i.e. copy the <ul>) to ensure that you have a valid HTML being injected into your slider.
$(document).ready(function() {
$('ul > li > ul').hide();
$('.slider').hide();
// Menu
$('.menuNav > ul > li').on('click', function() {
// if active
if ($(this).hasClass('active')) {
$(this).parents().children().removeClass('active');
$('.slider').hide('slide', 200);
}
// if unactive
else {
$(this).addClass('active');
$('.slider').show('slide', 200);
$(this).siblings().removeClass('active');
// Show related list (changed: now we use HTML's native outerHTML object
$('.slider').html($(this).find('ul')[0].outerHTML);
}
});
});
.slider {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<div class="slider"></div>
<div class="menuNav">
<ul>
<li><span>item_1</span>
<div class="sub_position">
<ul>
<li>sub-item_1-1</li>
<li>sub-item_1-2</li>
<li>sub-item_1-3</li>
<li>sub-item_1-4</li>
</ul>
</div>
</li>
<li><span>item_2</span>
<div class="sub_position">
<ul>
<li>sub-item_2-1</li>
<li>sub-item_2-2</li>
<li>sub-item_2-3</li>
<li>sub-item_2-4</li>
</ul>
</div>
</li>
</ul>
</div>
You have to fix this line
$('.slider').html( $(this).find('ul') );
I am not sure what you are trying to achieve here, but you cannot treat a DOM object as HTML code. The reason your code works once is that this line is does not fire the first time (your first IF statement fires). The second time ELSE kicks in and this evil line messes things up.
Solution 1: Comment out or remove this line
//$('.slider').html( $(this).find('ul') );
Solution 2: Figure out what you want to do with this line and do it the proper way.
I am trying to highlight the current page link, like this...
Image Here
Thanks to the others before me who have asked this, I have been able to do so properly.
But, My Navigation Bar has a sub menu.
I am trying to highlight the parent of the sub menu whenever I am in it. But, whenever I am from a parent menu (example the "MAIN") and went to a sub menu from a different parent (example the "TRANSFEREES") this happens...Image Here
here is the html for the menu...
<ul id = "nav">
<li>MAIN</li>
<li>ABOUT US</li>
<li>ADMISSION
<ul class = "sub">
<li>FRESHMEN</li>
<li>TRANSFEREES</li>
</ul>
</li>
</ul>
Here is the Javascript code...
$('ul#nav li a').click(function(){
$(this).closest('ul#nav li').addClass('active').siblings().removeClass('active');
return false;
});
And the CSS...
ul#nav li.active{
background:#9993a6;}
I have tried looking for a solution for this everywhere, I am a newbie at Javascript so if any of you could help me... I would really appreciate it... Thanks in advance.
The way you are removing active class is wrong, because addClass does not return a jQuery object, so you cannot use siblings() on it.
I also think is better to use parents instead of closest, you should try something like this:
$('ul#nav li a').click(function(){
var listElement = $(this).parents('ul#nav li');
listElement.addClass('active');
listElement.siblings().removeClass('active');
return false;
});
Try removing the active class for every list item in the list and it's sublists, and then add the active class to the items you want, otherwise you'll have to control too many cases.
This is the code:
$('ul#nav li a').click(function(){
$('#nav li').removeClass('active');
$(this).addClass('active');
var possibleParent = $(this).parents('#nav li');
if (possibleParent) possibleParent.addClass('active');
});
And here a Codepen demostrating: http://codepen.io/anon/pen/jWORRG
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.
Friends, I am working on JavaScript for collapse/Expand <UL> list.
here is my Code. I am wanted to work on it, in Nth Level, i can show Child, but its not hiding Children.
I hope you guys will help me..
Thanks in Advance...
This will do the trick:
event.stopPropagation();
Docs.
If you debug your code you'll see that the event is being called for each parent ul. Check this out:
$("#ExpList ul li:has(ul)").click(function(event) {
event.stopPropagation();
$(this).find('> ul')
.toggleClass("hiddenChild")
.toggleClass("displayChild");
});
And the HTML:
<div id='ExpList'>
<ul>
<li>Platform-1
<ul class='hiddenChild'>
<li>Child-1
<ul class='hiddenChild'>
<li>P-C-C-1</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
Fiddle.
HTML considerations:
I don't know if you can use a div wrapping the whole list, but I think it would make more sense doing it;
You're using the id ExpList for all ul. This is not how we use an id. Instead, for selecting many elements use its own tag or a common class;
I removed the onClick = openChild() which were present in all ul. It was throwin an error in your fiddle.
JavaScript considerations:
You don't have to mix a selector with a find this way $("#ExpList").find('li:has(ul)'). You can just use it on the same selector, as I did $("#ExpList ul li:has(ul)");
You don't need to search for all ul children($(this).children('ul')) since you'll have just one, I used this instead, which looks for just one: $(this).find('> ul');
As said before, the event.stopPropagation() does the trick. You don't need to trigger click event on all parent ul.
In CSS, I just changed #ExpList to this #ExpList ul to work in the new structure. I hope it helps.
I am trying to toggle list based on if a link is hovered on.
Here is my jQuery
$(function(){
$('.lists li').hover(function(){
$('ul.list-display', this).toggle('slow');
});
});
Here is my HTML:
<ul class='lists'>
<li><a href='http://eloquentjavascript.net/2nd_edition/preview/01_values.html'>Values, Types, and Operators</a>
</li>
<li><a href='http://eloquentjavascript.net/2nd_edition/preview/02_program_structure.html'>Program Structure</a>
<ul class='list-display'>
<h6>Test Sections</h6>
<li>Test</li>
<li>Test</li>
</ul>
</li>
</ul>
The problem is, it toggles down whenever you hover over the li which spans fairly far across the page, so whenever you hover into that li, it fires the toggle function. Ideally I would like the hover to fire when the mouse is over the link with the ul, not over the whole area of the li.
I think I have to alter my first selector in my function but so far all of my attempts have failed.
I see that you used this to give a context to the ul, but that's why it didn't work when you changed it to trigger off the a. Instead, just traverse the DOM like this:
$('.lists li a').hover(function(){
$(this).parent().find('ul.list-display').toggle('slow');
});
$(function(){
$('.lists li a').hover(function(){
$('ul.list-display').toggle('slow');
}
);
});
This appears to be working
http://jsfiddle.net/z6LP5/
It is because your code is working for the list item. Not the hyperlink.
$(function(){
$('.lists li a').hover(function() { // reach the hyperlink
$('ul.list-display').toggle('slow');
}
);
Now this would execute when you hover over the hyperlink (a). And then it would toggle the unordered list with the className of list-display.