Could someone clarify why the code below returns #text instead of 'li'
?
Shouldn't the next sibling of first li be li ?
Similarly previous sibling of last li be li ?
<body>
<ul>
<!-- comment -->
<li id="A"></li>
<li id="B"></li>
<!-- comment -->
</ul>
<script>
//cache selection of the ul
var ul = document.querySelector('ul');
//What is the nextSibling of the first li?
console.log(ul.querySelector('#A').nextSibling.nodeName); //logs text
//What is the previousSibling of the last li?
console.log(ul.querySelector('#B').previousSibling.nodeName); //logs text
</script>
</body>
The whitespace between the two is also a node. That's why JS libraries exist. To give you options like retrieving element siblings.
If the HTML source looked like this:
<ul>
<li id="A"></li><li id="B"></li>
</ul>
It would work as you expect it, because there's no whitespace between the li elements.
More recently, two more properties have been introduced, called previousElementSibling and nextElementSibling, which ignore that whitespace. It works from IE9 and up, with the other major browsers supporting it for a while now.
beter is use 'nextElementSibling' and 'previousElementSibling'
Related
I have just started my career. I got one requirement of getting the value inside an anchor tag which is inside div, ul and li tags.
<div class="abc">
<ul><li><a>Test</a></li><li class="selected"><a>Test</a></li><ul>
</div>
I want to fetch the anchor tag value which is under li tag having class selected using javascript. The hierarchy starts from div-ul-li
I know to get the values by using document.getElementyId, but this looks like complex for me
Any ideas would be very helpful for me.
If I understood you correctly, you need to use the whole hierarchy?
In this case, querySelector is your friend. The query looks like this:
querySelector('div.abc > ul > li.selected > a').
In detail that means:
div.abc gets us the div with the class abc
> refers to a child element of the element left to >, so we referr to ul which is a child node of your div abc
Now we want the div with the class selected which is a child node of ul, so we use > again
Last but not least we want to access the a tag inside of the div selected. Again we'll do that by using >
var text = document.querySelector('div.abc > ul > li.selected > a').textContent;
console.log(text);
<div class="abc">
<ul>
<li><a>Test</a></li>
<li class="selected"><a>Test</a></li>
</ul>
</div>
I have this part of HTML:
<div id="menu">
<ul>
<li>Startseite</li>
<li class="active">Brillengläser</li>
<li>Komplettbrille</li>
<li>Sportbrillen</li>
<li>Marketing</li>
<li>Statistik</li>
</ul>
</div>
I want to remove class="active" parameter and set it in li tag where I have href="/pacmodule/completeglass" atribute.
First part I successfully done with jquery:
$("#menu").find("ul:first").find(".active").removeClass("active");
But I have problems with second part. This select just a tag:
$('a[href="/pacmodule/completeglass"]').parent().html();
And this all ul tag:
$('a[href="/pacmodule/completeglass"]').parent().parent().html();
How can I set class="active" attribute in li tag where href="/pacmodule/completeglass"
Thank you for help.
You do not need the html() calls. They just return the innerHTML as a string. You probably expected that would return the outerHTML (for the outerHTML use something like ...parent()[0].outerHTML)
Try this:
$('a[href="/pacmodule/completeglass"]').closest('li').addClass('active');
It will find the anchor based on the href = "/pacmodule/completeglass", then find the closest ancestor that is an LI, then add the class active to it.
closest is the most useful way to find an ancestor of a specific type. It is better than using parent() as closest copes with the HTML structure changing.
Note: If you explain the overall aim, there may be better ways to do this than searching for the link href :)
Update
You do not want to remove the previous selection with this as it is too specific:
$("#menu").find("ul:first").find(".active").removeClass("active");
try this instead:
$("#menu li.active").removeClass("active");
.closest()
$("li").removeClass("active").find($('a[href="/pacmodule/completeglass"]')).closest('li').addClass('active');
DEMO
Easily do this (into your js document):
$("#menu li").removeClass("active");
$('a[href="/pacmodule/completeglass"]').parent().addClass("active");
$("#menu").find("ul:first").find(".active").removeClass("active");
This can be made more effective writing it as:
$("#menu").find("li.active").removeClass("active");
Then the DOM dont need to search for any ul, instead it goes directly to the class .active
why don't you try this :
$("#menu").find("ul:first").find(".active").removeClass("active");
$('a[href="/pacmodule/completeglass"]').parent().addClass("active");
you might wanna check this fiddle
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.
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/
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")