jQuery selector and cloning in a smart fashion - javascript

I am having trouble finding the way to solve this issue. I have this ul-menu output by Wordpress:
<ul class="menu">
<li>
Page 1
</li>
<li>
Page 2
</li>
</ul>
But I want the end result to be like this - cloning and appending the anchor and put a clone below:
<ul class="menu">
<li>
Page 1
Page 1
</li>
<li>
Page 2
Page 2
</li>
</ul>
I have used jQuery - but I am not having any luck at all for 2 hours of trial and error. This is as close as I can get. But it is wrong.
/*jQuery*/
$('.menu li a:first-child').eq(0).clone().insertAfter('.menu li a:first-child');
Fiddle here: http://jsfiddle.net/67jXz/1/

You're not supposed to .eq(0); that will limit it to the first a element that's matched, so that will be cloned and inserted after every subsequent a, resulting in copies of "Page 1".
Instead, you need to perform the cloning and inserting for each individual element by iterating with .each(), like so:
$('.menu li a:first-child').each(function() {
$(this).clone().insertAfter(this);
});
Note that the .insertAfter(this) part refers to inserting the cloned element after the original element that was matched by the .menu li a:first-child selector; the same this in $(this) that references the matched element.
Updated fiddle

Try this code:
$(function(){
$('.menu li a:first-child').each(function(k,v){
$(v).clone().insertAfter(v);
});
});
jsfiddle

Related

jquery: Trying to understand the next() function

I was using the jquery next() method on the following html:
<div id="NavBar">
<div class="dropDownList">
<ul>
<li><span>Home</span></li>
<li><span>Products</span>
<ul>
<li><span>test</span>
<li><span>test</span>
</ul>
</li>
<li><span>Company</span>
</li>
<li><span>Contact</span></li>
</ul>
</div>
<div class="dropDownList">
<ul>
<li><span>Home</span></li>
<li><span>Products</span>
</li>
<li><span>Company</span>
</li>
<li><span>Contact</span></li>
</ul>
</div>
</div>
I added the following click handler to anchors in the list and wrote the current and next() element to the console like so:
$('.dropDownList > ul > li > a').click(function() {
console.dir($(this));
var checkElement = $(this).next();
console.dir(checkElement);
}
When I click the "Products" list item of the first ul I see this in the console:
So I can see the first element is the anchor and the next is the ul- this makes sense to me. Now my confusion comes in when I click the "Products" list item in the second ul. I get back two objects like before, but this time they are both anchors. I thought that the first anchor element would be "Products" and the second would be "Company" because that is the next element in the list- or maybe even the <li> element containing the next anchor. Instead when I drill down into the objects in the console they appear to be the same element. The text and textContent field is the same for both:
Why is this?
In your second example, the next element in the list is not a sibling to the a anchor; it's a sibling to its parent li.
That Products anchor has no .next() element, and you should see in your console that $(this).next() is an empty jQuery object with zero .length. http://jsfiddle.net/mblase75/6LFPG/
So the problem is that in your a anchor has no next() it will return null. So in that case you will have to go up to the parent and get the next sibling. Here is a really quick rough example on how it can be done.
var CheckElement;
if($(this).next().length != 0){
checkElement = $(this).next();
}
else{
checkElement = $(this).parent().next();
}
the JQuery next() method brings you to the next sibling of the selected element.
Siblings are those that elements that have the same parents.
From your given html
<li><span>Products</span> //child of 'li'
<ul> <----------------------------------//child of 'li'
<li><span>test</span>
<li><span>test</span>
</ul>
</li>
What you selected was the first child.
So when you called next in the first example it selected the next child.
In your second example there is no second child to traverse therefore it defaults to an empty jquery element.

Select LI children from a not none-displayed UL

The title sounds strange but what I want to achieve is simple.
In a tree of uls I want to get all li children from any ul that have not the - inline - style display: none. So I found this post and I mixed with the negation function :not(). The result was:
'ul:not([style*="display: none"]) .k-item'
Where .k-item is a common class for all my li elements. That selector worked in this simple fiddle. The problem is that it doesn't works in my application. I have a screenshot of some console commands that will illustrate my scenario:
As you can see on second command, it returns some li elements that lies under an ul which haves display: none among other attributes in its inline style. Example of those unexpected li with attribute data-uid with values starting with 099d, bbca and 14d2.
I don't know what I'm doing wrong or if exists a better selector for that purpose.
I would suggest using jQuery's :visible rather than looking for something in the style string and string matching in the style string could be problematic.
$("ul:visible .k-item")
First of all get all the li and check whether its parent (ul) is visible.
jsfiddle
$('li', '#layers').each(function(){
if($(this).parent().is(":visible")){
alert($(this).text())
}
});
OR
a neat version
jsfiddle
$(".k-item:visible").each(function(){
alert($(this).text())
});
Try using
$('ul:not([style*="display: none"]) li.k-item').each(function() { alert($(this).html()) });
HTML
<ul style="display: none">
<li class="k-item">1</li>
<li class="k-item">2</li>
<li class="k-item">3</li>
</ul>
<ul>
<li class="k-item">4</li>
<li class="k-item">5</li>
<li class="k-item">6</li>
</ul>
Fiddle: http://jsfiddle.net/3M2ZM/

Detect class inside ul list, if not found delete li:first-child

I have this structure:
<ul id="#my-list">
<li><a class="class-1" href="#">Link</a></li>
<li><a class="class-2" href="#">Link</a></li>
<li><a class="class-3" href="#">Link</a></li>
</ul>
I want jquery to check if .class-1 inside #my-list exists, if not then it should delete .li (just the first one).
Basically, when the first link is deleted, the first li element should be removed as well.
$('#my-list:has(.class-1) li:first').remove()
That would of course require an ID like:
<ul id="my-list">
FIDDLE
According to your question, you'd like to do the opposite for some strange reason, and that would be :
$('#my-list:not(:has(.class-1)) li:first').remove()
but the question is, how are you deleting the anchor, and why not just delete the list item instead ?
Basically, when the first link is deleted, the first li element should be removed as well.
Sounds like you want:
$('#my-list > li').first().filter(function() {
return $(this).find('a').length === 0;
}).remove();
If you want to apply this to all li elements, not just the first one, simply omit .first().

Add return false to parent link only with jQuery

I have a list inside a toggled div...
<li>
Link
<ul stlye="display:none;">
<li>Child Link</li>
</ul>
</li>
Ive written a piece of jQuery to toggle the display of the child UL only when a child link is clicked it no longer works (It doesnt go through to google), can anybody see where im going wrong?
// Dropdown
$('.archives ul li a').click(function(){
$(this).parent().find('ul').slideToggle();
return false;
});
STYLE is spelled wrong.
stlye=
From your post's title it appears you want something like this...
$('.archives ul li a').click(function(){
var $children = $(this).parent().find('ul');
$children.slideToggle();
return $children.length > 0 ? false : true;
});
Return will be false only when child ULs are found.
Assuming what you've shown is inside a ul which is in turn inside an element with class archives, then the selector .archives ul li a matches both the parent and child anchors, because you've used a descendant selector, and so your handler gets called for the child, and the return false; prevents it from doing its default action (following the link).
If your goal is to have the handler triggered only for the earlier link and not for the child link, then you may need to be more specific. You haven't shown enough of your markup for us to help you be more specific, though. If I assume your markup looks something like this:
<div class="archives">
<ul>
<li>
Link
<ul style="display:none;">
<li>Child Link</li>
</ul>
</li>
</ul>
</div>
...then the selector to match only the "Link" anchor and not the "Child Link" anchor would be .archives > ul > li > a (e.g., using direct child selectors).
Also note that you had stlye rather than style, but I assume that's just a typo in the question. (Why don't people use copy and paste?! ;-) )
The ChildLink is also matched by your selector, and in the click handler you're preventing the default action (which would be "navigate to Google").
So you should adapt your selector to only get the toggle Link, or you use this:
$('.archives ul li a').click(function(e){
if ($(this).siblings('ul').slideToggle().length) // if we found a list to toggle
e.preventDefault(); // or return false
});
Since your return false statement is cancelling the default link action, you need to be more specific so that you don't target the links that want to allow to continue to function.
Try this:
$('.archives > li > a').click(function () {
$(this).parent().find('ul').slideToggle();
return false;
});
jsFiddle example
By using the > child selector and changing the target to only the immediate child links of the outermost list, the sublinks won't be selected and will continue to work. In your code your $('.archives ul li a') will apply to any child links, not just the top level.

How would I prevent JQuery from selecting more than 1 level of children dom elements?

How would I only select Item A and Item B pragmatically while excluding the sub item?
<div id="nav">
<ul>
<li>
<p>Item A</p>
<ul>
<li>
<p>Sub Item A</p>
</li>
</ul>
</li>
<li>Item B</li>
</ul>
</div>
Well after a quick test run - this is my contribution to this issue
$("#nav p:first, #nav > ul > li:eq(1)");
You specified that you wanted only those two items and no sub items so this is what jQuery will capture :
[<p>​Item A​</p>​, <li>​Item B​</li>​]
You can easily separate selectors by placing a comma between them.
Now that you have seen my solution I would strongly suggest that you take Xenon06's advice...
Giving your markup classes really helps you to keep track of them. Especially with jQuery. The class attribute while IMO mostly used for styling is a perfectly valid selector to use and abuse in your jQuery code. That is of course if you actually have access to that HTML. If you don't kindly ignore my last paragraph :)
This will select any first level li's that have only text and no children and any children of a li that isnt a ul. Given this is not a good way to do it. You should really put classes on your stuff to start with. But if that's not an option this will get you there.
$($('#nav').children()).children().each(function(){
if($(this).text() !== "" && $(this).children().length === 0 ){
$(this).addClass("IwantThisElement");
}
});
$($($('#nav') .children()) .children()) .children(':not(ul)').each(function(){
if($(this).text() !== ""){
$(this).addClass("IwantThisElement");
}
});
$('.IwantThisElement').text('Assuming Control');
Well, if your structure was more consistent, you could use direct children selectors, ie:
$("#nav ul li > p")
However your Item B is not in a paragraph. Without defining more what you want, you'll need to put classes on the items you want and do
$("#nav .yourclass")

Categories