I'm working on a menu that is designed using an unordered list, with each list element containing a link to another page. However, I would also like to be able to click on each bullet point to open more subcategories that will also link to other pages.
Essentially, I would like to be able to click once on a link and have it go to the correct page, but I would also like to click on the bullet point and have it expand into the subcategories. I've been researching how to separate the bullet from the content of the li, but it doesn't seem to be working in my case, likely because my li contains a lot of subcategories. Here's an example:
<li id="m2l1" class="child">
Y
<ul id="u11">
<li class="gchild">Y.1</li>
<li class="gchild">Y.2</li>
<li class="gchild">Y.3</li>
<li class="gchild">Y.4</li>
<li class="gchild">Y.5</li>
<li class="gchild">Y.6</li>
<li class="gchild">Y.7</li>
<li class="gchild">Y.8</li>
<li class="gchild">Y.9</li>
</ul>
</li>
Does anyone have any suggestions as to how to separate the bullet from the text in my case?
Here's the link: http://jsfiddle.net/stamblerre/XYp48/17/
Thank you!!!
Your HTML is invalid. You can't have div inside your ul. Moreover, you can greatly simplify your code by moving separate logic for each li into one generic handler.
Something like this:
Demo: http://jsfiddle.net/abhitalks/XYp48/18/
CSS:
ul {
display: none;
overflow: hidden;
}
ul:first-child {
display: block;
}
JS:
$("li").on("click", function () {
$(this).children("ul").slideToggle();
return false;
});
Edit:
I deliberately left out checking of a because clicking the a would navigate to the respective pages (as mentioned in your question), so expand/collapse wouldn't matter.
However, as per your comment if you really want to remove a altogether from the handler, then you can use the event target to handle li without a. Something like this:
Demo 2: http://jsfiddle.net/abhitalks/XYp48/22/
JS:
$("li").on("click", function (e) {
var $t = $(e.target); // get the event target as a jQuery object
if (!$t.is('a')) { // check if the target is not an anchor
$(this).children("ul").slideToggle();
return false;
}
// otherwise if target is anchor, then do nothing
});
Change your list still to hide bullets, then modify your html to :
<li class="gchild">•Y.1</li>
Should do the trick.
<li class="gchild">Y.1</li>
One way that worked for me: remove the bullet with li { list-style-type: none; } then add your own bullets with the character • (alt-8 on a mac). Add that character inside a elements like so:
• X
with the label now outside of the element.
Hope this works for you!
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 have a menu in HTML and it looks like this:
<nav>
<ul>
<li>Home</li>
<li>About
<ul>
<li>Team</li>
<li>Philosophy</li>
<li>History</li>
</ul>
</li>
<li>Projects</li>
<li>Services
<ul>
<li><a href="#">Our Service</li>
<li>Special Offers</li>
</ul>
</li>
<li>Contact</li>
</ul>
</nav>
Everything is in shape via CSS except one thing: to get the submenu to appear when its parent list-item's link points to the same address as the current page address.
I know this is possible somehow. But I really am the greatest noob with JavaScript or jQuery or PHP (I think the last two mean the same thing right?).
I tried copying and pasting code pieces like "OnClick=..." and one that was like "" or also one I found that contained "GetElenentbyTagName" (which almost worked...) but besides that I had no real clue about where to put them even. They just didn't work properly or not at all. I had a full done code piece but when I pasted it in and replaced some tag names it all got got marked red and my head is burning after trying to get it to work for the entire day.
I think this is possible because I have seen things that seemed to be describing part of what I want to do. E.g.
The script piece should either
Option A: Tell the browser that if the user is on a page which has the same address as a link in the menu it's href-address is, then it's submenu (ul li ul) or the menu (ul) where itself is contained in, should get "visiblity:visible".
Option B:
The script code says like "if the user clicks on an menu item (ul li), then it's submenu (ul li ul), if it has one, or if the menu-item that is being clicked is one of the submenus, then this submenu should become "visibility:visible". If the item that is clicked doesn't have a submenu, no submenu should be shown.
The HTML code must not have classes or other attributes directly anywhere between (nav) and (/nav) though.
I do not have sure if i understand what you need,
you need when user go to some menu page it get the url and active that link on menu until the user is on that page right?
if is that,
i think something like that should work:
<script type='text/javascript'>
$(function(){
$item = $('ul li a').filter(function(){
return $(this).prop('href').indexOf(location.pathname) != -1;
});
$item.css('visibility','visible'); //or whatever ur using to active it.
});
</script>
You can do this with CSS:
li ul {
display: none;
}
li a:hover + ul {
display: block;
}
http://jsfiddle.net/7bxf6r33/
[Edit]
This works:
http://jsfiddle.net/7bxf6r33/7/
I built this website http://www.graphink.be where I use the OnepageScroll Plugin.
I came across the weirdest behaviour with the plugin.
I hooked a custom navigation to the scroll effect.
When I click the nav links, following DOWN the sections, the plugin will automatically skip one section at each click.
Meaning : click on the 2nd link, it will move to the 3rd, click on the 3rd and it will move on to the 4th and so on, creating a blank section when clicking on the last link.
The weirdest thing is that it seems to be working fine following UP the links...
here's the small js I created for the custom nav:
$(document).ready(function(){
$("nav > input").click(function(){
$(".content").moveTo($(this).data("target"));
});
// Set up nav bar
// ---------------------------------------------------------------------------
$("#logo").on('click', function(){$(".content").moveTo(1);});
$(".arrow").on('click', function(){
$(".content").moveDown();
});
$("#nav_home").on('click ', function(){$(".content").moveTo(1); });
$("#nav_work").on('click ', function(){$(".content").moveTo(2);});
$("#nav_about").on('click ', function(){ $(".content").moveTo(3); });
$("#nav_contact").on('click ', function(){$(".content").moveTo(4);});
});
I obviously made a mistake somewhere, but I just can't find it...
I would try getting the section index from the element clicked and make sure the index is always correct:
$('nav li a').click(function(e) {
var sectionIndex = $(this).data("target");
console.log(sectionIndex); // print to check
$('.content').moveTo(sectionIndex);
});
It seems to me that the section index starts on 0. As it always does in javascript or jquery. Although it's not very clear in the docs...
$.fn.moveTo(page_index)
This method allows you to move to the specified page index programatically.
Change the data-target attribute to one number less on each.
<ul>
<li> Home</li>
<li> Work</li>
<li> About</li>
<li> Contact</li>
</ul>
If you still having troubles, I would recommend you to try fullPage.js which integrates a menu option and many other useful options and configurations.
I think it has something to do with href attribute of "a"
Try to remove #intro #work #contact and #about from "a" elements of your navigation
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 have 6 list items
$('.favorite-tag-group li').each(function(){
console.log("hi");
});
This code however is displaying "hi" 24 times in console.
The only thing I can think of that might be causing it to bug out is because my list items arent all in the same list.
For example, .favorite-tag-group is a div that always contains a ul. In some cases, that ul will only have 1 li. Sometimes it may have 2.
Here's a sample of what that might look like
div.favorite-tag-group
ul
li
li
li
div.favorite-tag-group
ul
li
div.favorite-tag-group
ul
li
div.favorite-tag-group
ul
li
li
All I'm trying to do is run through .each() li so that I can remove duplicates ;/
Some real html:
<div class="favorite-tag-group">
<h4>gobty</h4>
<ul class="resources led-view">
<li class="clearfix r-tutorial" data-id="22">
</li>
</ul>
</div>
<div class="favorite-tag-group">
<h4>javascript</h4>
<ul class="resources led-view">
<li class="clearfix r-tutorial" data-id="24">
</li>
</ul>
</div>
<div class="favorite-tag-group">
<h4>macvim</h4>
<ul class="resources led-view">
<li class="clearfix r-tool" data-id="21">
</li>
</ul>
</div>
here is the real function. When i paste the .each() directly into console it works, but inside this function it doesnt work:
// collapse tags functionality
$('.collapse-tags').click(function(e){
e.preventDefault();
$('.favorites-helpers, .favorite-tag-group h4').slideUp(200, function(){
var seen = {};
$('.favorite-tag-group li').each(function(){
//console.log("hi");
var currentId = $(this).data('id');
if (seen[currentId]) {
$(this).slideUp(200);
} else {
seen[currentId] = true;
}
});
});
});
As in my comment above... With a bit of further explanation.
It's because $('.favorites-helpers, .favorite-tag-group h4') will be causing multiple elements to slideUp(), and therefore the callback gets executed multiple times. Moving var seen = {} to inside the callback resets the variable as an empty object in each callback. You'll still iterate over your list items more than once (as seen by multiple console.log()s), but you'll slide the same duplicate li's up each time this way.
You asked: "The one thing im still confused about is, why would it not be able to see the scope of seen if it were outside the callback? wouldnt variable scope say that it could see it because its outside the function?"
Yes, you are right - the callback could see seen, but seen was never emptied/reset, and therefore after the second iteration of your callback, all of your li's would have had .slideUp() called on them.
Consider this: because it either slides the duplicate up, or adds the id to seen, on the second callback, .each() runs again, but it's already full of all of your list items ids.
Hope this is clear enough, if not just comment below and I'll try and come up with some examples.
Here you are, sir...
$(document).ready(function(){
$("div.favorite-tag-group>ul").children("li").each(function(index,element){
//code here
//refer to element as $(element)
//to get the id of the element use: $(element).attr("id");
});
});
Demo: http://jsfiddle.net/9uz8k/11/
Link:
http://api.jquery.com/each