Hi I am trying to target "this" child descendant of "this."
Below is a list that contains sublists.
What I am trying to accomplish is an understanding of how to select this child of this parent.
Basically when I click on Honda, the sublist expands and I want to console.log the text of each selected element when I click it. For simplification purposes I changed the code to a console.log.
So far what the code below returns is the text for everything within the li.
IE if I click Honda or If I click Accord, the console returns the values "Honda, Accord, and CRV."
How would I traverse "this" to get the text of the clicked child of "this". The "this" of "this".
IE if I select "Accord" using my code below it should return the text "Accord" alone.
Code:
<ul class="main-menu">
CARS
<ul>
<li class="has-subs">
Honda
<ul class="sub-menu">
<li>Accord</li>
<li>CRV</li>
</ul>
</li>
<li class="has-subs">
Ford
<ul class="sub-menu">
<li>Mustang</li>
<li>Explorer</li>
</ul>
</li>
</ul>
$('body').on('click', '.main-menu ul li', function (e) {
e.preventDefault();
$this = $(this);
console.log($this.text());
if ($(this).find("a").text() == "CRV") {
var subMenu = $this.siblings('.sub-menu');
console.log("'THIS' SELECTOR IS WORKING AS INTENDED!");
}
})
Update:
Thanks all for answering! I think it will help to explain further what I am trying to accomplish.
What I am ultimately am trying to get sorted out is that I have a master accordion list with a list of car manufacturers and each manufacturer has a submenu like shown above.
I want to click on a list item, say Honda, it expands only Honda's list and shows their makes ie Accord and CRV. Then when I click on either Accord or CRV, it goes to their respective webpages.
When I click on a Ford, Honda's list should collapse or be hidden and Ford's should expand.
Here's a solution that makes your code work with minimal changes, however note that this setup is problematic since it creates a new (duplicate) event listener on every click.
$('body').on('click', '.main-menu ul li', function (e) {
e.preventDefault();
$this = $(this);
console.log($this.text());
$this.on('click', 'li', function(e) {
if ($(this).find("a").text() == "CRV") {
var subMenu = $this.siblings('.sub-menu');
console.log("'THIS' SELECTOR IS WORKING AS INTENDED!");
}
})
})
As #freedomn-m pointed out, your selectors are probably too broad. I'm not exactly sure what you're ultimately trying to do with the line selecting the sub-menu, but here's an alternate solution that's cleaner:
$('.has-subs>a').click(function(e) {
e.preventDefault();
console.log($(this).parent().text());
});
$('.sub-menu>li>a').click(function(e) {
e.preventDefault();
console.log($(this).text());
});
jsbin: http://jsbin.com/lurutiwago/edit?html,js,console,output
Your current selector
.main-menu ul li
will find all ul/li, under .main-menu, so will match Honda and Accord/CRV.
If you want to only act on the top-level items (Honda), you can change your selector to be more specific:
.main-menu>ul>li
(assuming they're correctly inside .main-menu).
Or, if you only want the lower ones:
.main-menu>ul>li>ul>li
or, in your case, target the 'ul' directly
ul.has-subs>li
or
ul.sub-menu>li
Related
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!
I have the following code:
<div id="nav">
<ul>
<li id="tabOne" class="first current">Page One</li>
<li id="tabTwo">Page Two</li>
<li id="tabThree"><a href="./CS3.html" target="SheetView">Page Three</li>
<li id="tabFour">Page Four</li>
<li id="tabFive">Page Five</li>
<li id="tabSix">Page Six</li>
</ul>
This loads the selected page into an iframe named "SheetView." What I need to do is use JavaScript to alter the class when an option that isn't the currently selected on is clicked. I should say that I have the current class already setup in my CSS. I just have no way to trigger it.
I thought adding an onlick event to the <UL> up there and calling onclick="Javascript:changeCurrent();" but there is the problem (four actually):
Is <ul onclick="JavaScript:changeCurrent();> where I need to have the event?
What is the resulting JavaScript to make the change happen?
How can I cause the first option to be set as current by default?
Is there a way to keep the currently selected option from being an active link?
I found a few different examples but I couldn't tailor them to work for me. Any help would be most appreciated.
Since you specified that you wanted a non-jQuery response, here's a function that will toggle appropriately:
function toggleNavSelected(el){
var list = document.getElementById('nav').children[0];
for(var i=0; i<list.children.length; i++){
var cur = list.children[i];
if(el==cur){
cur.classList.add("current");
cur.firstChild.onclick = (function(){
toggleNavSelected(this.parentElement);
return false;
});
} else {
if(cur.classList.contains("current")){
cur.classList.remove("current");
}
cur.firstChild.onclick = (function(){
toggleNavSelected(this.parentElement);
});
}
}
}
Either add an onclick handler to each LI (onclick="toggleNavSelected(this);") or execute the following after the menu has loaded:
var list = document.getElementById('nav').children[0];
for(var i=0; i<list.children.length; i++){
var el = list.children[i];
el.firstChild.onclick = (function(){
toggleNavSelected(this.parentElement);
});
}
Demo: http://jsfiddle.net/bWY7P/2/
(note: The JSFiddle script has a small difference; it adds a return false; to the onclick function so that you can play with it without the links actually following the HREF attribute. Do not use that line in your live code)
Explanation:
The function looks at each LI element within the #nav element.
If that element is the element passed to the function, then it adds the class .current.
Otherwise, it removes the class .current (if present).
The second part binds a function to the onclick event of each a element that calls the toggleNavSelected() function and passes its parent element (the li) as the argument.
1) if you want to change the currently selected class when you click an item, put the onclick into the li item
2) using jquery would be very easy here, all you have to do is import the jquery file with the <script> tag and you're ready! For example, you could do onclick="changeClass(this);" on the <li> tag and in a normal JavaScript file or in a script tag:
function changeClass(this){
$('#nav li').attr("class","");
$(this).attr("class","current");
}
Replace the 'current' with the class name you want to use
3) it should already be set as current
4) use the :visited CSS selector to change what colour followed links look like eg:
a:visited{
color: #000000;
}
First of all you should set the event handler from a separate script, not from an onclick attribute. You don't repeat your code that way and have anything in one place. The HTML is also much cleaner.
Using jQuery it would be as easy as:
var menuLinks = jQuery( '#nav a' );
menuLinks.on( 'click' function() {
menuLinks.removeClass( 'active' );
$( this ).addClass( 'active' );
} );
You could also do that in plain JS, but using some library keeps you out of the trouble of browser incompatibilities.
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
I'm currently trying to select the previous closest list element within an <ul>
My current method works if there is > 1 <li> inside of it.
html:
<ul id="coaches" class="list">
<li><span>bob<a class="close"></a></span></li>
<li class="colored"><span>cobb<a class="close"></a></span></li>
</ul>
js:
$(this).closest("li").fadeOut("normal", function() {
$(this).remove();
});
How can I make it delete the previous closest list element with both the number of list element = 1 and > 1 elements? I tried adding a prev() and prevAll() chained after closest('li') but to no avail. Any ideas?
It should work as you have it in your example..
demo at http://jsfiddle.net/gaby/nZXxD/ for the code as it currently is
demo at http://jsfiddle.net/gaby/nZXxD/1/ for the code with a single li element..
The problem must lie somewhere else..
(are you sure the event is bound correctly? and after the DOM is ready ?)
$(function(){
$('a.close').click(function(){
$(this).closest("li").fadeOut("normal", function() {
$(this).remove();
});
});
});
it just working fine with prev()
check the link http://jsfiddle.net/ABqpN/5/
Assuming $(this) is referring to the "a" tags inside "span" inside "li", and assuming that when you click on the "a" it's parent "li" should get removed, you can do this:
$(this).parent('li').fadeOut("normal", function() {
$(this).remove();
});
I have a list with links:
<li class="link-1">One</li>
<li class="link-2">Two</li>
<li class="link-3">Three</li>
..
user clicks on any link, then with jQuery I want to display the content of the link.. somthing like:
$(".link-??? a").click(function() {
alert($(".link-??? a").html());
})
something like this. I am not going to create X function (as the number of the links), so what can I do? I should replace the ??? in somtehing else..
You could do:
$('li[class^="link"] a').click(...
However this would only work if the li have only one class or if the link-X class is the first in the list.
Inside the handler you can use $(this) to refer to the a element:
alert($(this).text());
Much better would be to give the li elements a common class:
<li class="link">One</li>
<li class="link">Two</li>
<li class="link">Three</li>
$('.link a').click(... will be much more reliable.
Give each element the same class. Then in your javascript reference this within your function. Check out the link below to see a working example
http://jsfiddle.net/kprgr/2/
<li class="link">One</li>
<li class="link">Two</li>
<li class="link">Three</li>
$(".link").click(function() {
alert($(this).find("a").html());
});
Try..
$(".link-??? a").click(function() {
alert(this.innerHTML);
})
Inside the click event, this should refer to the element that was clicked.
You could also do..
alert($(this).html());
..but the first way is simpler, and faster.