JQuery Prepending text in front of a link - javascript

I have a unordered list with links and sublinks. I'd like to prepend a '»' character in front of the sublinks in the list. I could probably do this with CSS via list-style-image:url but I'd rather just have text. So far I have tried prepend without much success.
HTML:
<nav>
<ul>
<li>link 1</li>
<li>link 2</li>
<ul>
<li>sublink link 1</li>
<li>sublink link 2</li>
</ul>
<li>link 3</li>
</ul>
</nav>
And I am using this code:
$("ul li li").each(function() {
$(this).closest('li').prepend("»").html();
});
If I take away one level of list items and prepend to all list items, then it works but viewing in web inspector, the » character still has quotes around it. I also tried various incarnations of what appeared for closest such as li a but that did not make a difference either. I'm not getting any syntax errors so not sure what I am doing wrong.
I have a Fiddle here.

Why not some css?
ul ul li:before {
content: '»';
}
Using JavaScript to modify the UI for something like this is a waste of resources. This is subjective without knowing your actual use case.

Your selector is not correct, also there is no need to use html and each methods.
$("ul ul li").prepend("»");

You had an incorrect selector ul li li implied there was an li directly within an li but there is another ul between.
In addition you don't need to use a .each for that as jQuery will return the reference to the set of elements which matched the selector.
$("ul ul li").prepend("»");
DEMO
Mind you the CSS solution from Aknosis looks very cool.

I think this is what you are needing:
$("ul ul li").prepend("» ");

Try:
$("ul li").each(function() {
$(this).prepend("»").html();
});

Related

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/

jQuery selector and cloning in a smart fashion

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

Add different classes to list item parents using jquery

I have a list with different levels of depth:
<ul>
<li>Item 1</li>
<li>Item 2
<ul class="sub-menu">
<li>Sub item 1</li>
<li>Sub item 2</li>
<li>Sub item 3
<ul class="sub-menu">
<li>Subsub item 1</li>
<li>Subsub item 2</li>
</ul>
</li>
<li>Sub item 4</li>
</ul>
</li>
<li>Item 3</li>
</ul>
I am using the following jquery script to add a class to the parents:
$("ul li ul").parent().addClass("menuparent");
Is there a way to add this class only to the top level parent li's and a different class for all other (deeper) parent li's?
Here is one way to do it.
$("ul li ul").parent().addClass("otherclass");
$("ul li >ul").parent().removeClass("otherclass").addClass("menuparent");
​
http://jsfiddle.net/MdBa5/
You could run a closest check to see if there are any parents that are li.
if ($element.closest("li").length === 0) {
$element.addClass("topLvl");
} else {
$element.addClass("innerLvl");
}
Try:
$("ul:first>li").addClass("menuparent")
.find('li>ul').parent().addClass('otherparent');
http://jsfiddle.net/3UcdM/
Here's a recursive solution:
function markNestedLists(par, level){
par.addClass("level-" + level);
par.children("li").children("ul").each(function(){
markNestedLists($(this), level + 1);
});
}
markNestedLists($("ul").first(), 1);
http://jsfiddle.net/h9xvY/1/
If you know the ID of the parent of the topmost UL you could use it like so:
markNestedLists($("#myParent > ul"), 1);
Depending on what you want the names of the classes to be, I'd use this:
$(function(){
$('ul li').addClass(function(){
return 'depth-' + $(this).parents('ul').length;
});
});​
You can see a working example here: http://jsfiddle.net/russelluresti/3peCS/
If you want special class names, and not number additions, you'd have to run a switch statement. But the concept is the same. Use a function inside addClass to determine the depth (by using parents()) and return the appropriate value.
Ideally, there's some absolute reference like an ID or other searchable attribute that is unique to the top-most ul, but you can work around that. Either way, the important thing is the child selector: > instead of the implicit descendant selector. It will specify that you only want to find ul's that are exactly so many levels below that top-level element.
When, in your base case, you use:
$("ul li ul").parent()
you get all ul's that are any descendant (children, grandchildren, great-grandchildren...) of any li's, that are descendant of any ul's. Instead, you'd use:
$("ul#topmost > li > ul").parent()
which gets you only a ul that is the child of an li that is a child of the specific ul at the top of the tree.
If you don't have an id or other explicit selector for the top of the tree, the top-level ul must itself be a child of either a div or body or some other block-level element. So, you can clearly and distinctly get the hierarchy you want by just adding that parent of the top-level ul:
$("body > ul > li > ul").parent()
Also: I forgot that you also wanted to be able to select the other parent li's that aren't captured by the selector above. You can do that using the :not selector, or JQuery's .not() method, like so:
$("li>ul:not(body > ul > li > ul)").parent()
To combine the two lines into one, you'd first add the deeperParent class to all such li's, then filter for the top-level parent, and assign menuParent only there:
$("li>ul").parent().addClass('deeperParent').filter('body > ul > li').
removeClass('deeperParent').addClass('menuParent')

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")

Jquery child selector vs. .each

Given the following example table:
<ul class="topnav">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
What are the differences between:
$selector1 = $('ul.topnav > li');
and
$selector2 = $('ul.topnav').each();
EDIT:
$selector2 = $('ul.topnav li').each();
The first will contain all li's which are a direct child of ul.topnav, the second will contain all ul.topnav elements.

			
				
$('ul.topnav > li') will select all <li>s directly under the ul.
each should take a function as a parameter, and iterate over all matched <ul> - it doesn't not take the children <li>s. If anything, you want $('ul.topnav').children(), which is identical if the ul only contains li elements anyway.
For example, this will alert the number of children each list has (in your case, only the number 3)
$selector2 = $('ul.topnav').each(function(){
alert($(this).children().length);
});
Also see the jquery API.
The second one will evaluate them individually, whereas the first one will evaluate them as a group

Categories