Let's presume you got a list with nested child lists.
<ul>
<li></li>
<li>
<ul>
<li></li>
<li></li>
</ul>
</li>
<li></li>
</ul>
And use document.querySelectorAll() to make a selection:
var ul = document.querySelectorAll("ul");
How can i use the ul collection to get the direct child elements?
ul.querySelectorAll("> li");
// Gives 'Error: An invalid or illegal string was specified'
Let's presume ul is cached somehow (otherwise i could have done ul > li directly).
In jQuery this works:
$("ul").find("> li");
But it doesn't in native querySelectorAll. Any solutions?
The correct way to write a selector that is "rooted" to the current element is to use :scope.
ul.querySelectorAll(":scope > li");
See my answer here for an explanation and a robust, cross-browser solution: https://stackoverflow.com/a/21126966/1170723
Because the ul returned is a NodeList, it doesn't implicitly loop over its contents like a jQuery collection. You'd need to use ul[0].querySelectorAll() or better still select the ul with querySelector().
Besides that, querySelectorAll() won't take a > and work from its current context. However, you can get it to work using lazd's answer (though check the browser compatibility), or any of these workarounds (which should have no browser issues)...
[].filter.call(ul.querySelectorAll("li"), function(element){
return element.parentNode == ul;
});
jsFiddle.
This will select all li elements that are descendants of your ul, and then remove the ones which are not direct descendants.
Alternatively, you could get all childNodes and then filter them...
[].filter.call(ul.childNodes, function(node) {
return node.nodeType == 1 && node.tagName.toLowerCase() == 'li';
});
jsFiddle.
You need to iterate over the NodeList returned by document.querySelectorAll() and then call element.querySelectorAll() for each element in that list.
Related
I have an unordered list and the index of an li tag in that list. I have to get the li element by using that index and change its background color. Is this possible without looping the entire list? I mean, is there any method that could achieve this functionality?
Here is my code, which I believe would work...
<script type="text/javascript">
var index = 3;
</script>
<ul>
<li>India</li>
<li>Indonesia</li>
<li>China</li>
<li>United States</li>
<li>United Kingdom</li>
</ul>
<script type="text/javascript">
// I want to change bgColor of selected li element
$('ul li')[index].css({'background-color':'#343434'});
// Or, I have seen a function in jQuery doc, which gives nothing to me
$('ul li').get(index).css({'background-color':'#343434'});
</script>
$(...)[index] // gives you the DOM element at index
$(...).get(index) // gives you the DOM element at index
$(...).eq(index) // gives you the jQuery object of element at index
DOM objects don't have css function, use the last...
$('ul li').eq(index).css({'background-color':'#343434'});
docs:
.get(index) Returns: Element
Description: Retrieve the DOM elements matched by the jQuery object.
See: https://api.jquery.com/get/
.eq(index) Returns: jQuery
Description: Reduce the set of matched elements to the one at the specified index.
See: https://api.jquery.com/eq/
You can use jQuery's .eq() method to get the element with a certain index.
$('ul li').eq(index).css({'background-color':'#343434'});
You can use the eq method or selector:
$('ul').find('li').eq(index).css({'background-color':'#343434'});
There is another way of getting an element by index in jQuery using CSS :nth-of-type pseudo-class:
<script>
// css selector that describes what you need:
// ul li:nth-of-type(3)
var selector = 'ul li:nth-of-type(' + index + ')';
$(selector).css({'background-color':'#343434'});
</script>
There are other selectors that you may use with jQuery to match any element that you need.
You could skip the jquery and just use CSS style tagging:
<ul>
<li>India</li>
<li>Indonesia</li>
<li style="background-color:#343434;">China</li>
<li>United States</li>
<li>United Kingdom</li>
</ul>
I'm having a problem selecting all the LI tags when converting jQuery code to HTML5 javascript
code. I have applied the click event to the parent UL, and the click event is being applied to the correct clicked target LI. The class "selected" is also being applied. The problem is that I need all classes to be cleared from the LI tags before the "selected" class is applied, as I only want it applied to the current event target. In jQuery it is simply a matter of removing classes from the LI's, but I am having problems targeting all the LI tags and removing the class in javascript. I suspect the problem is how I am iterating over the node list returned from QuerySelectorAll. I have also tried amongst other things, document.GetElementsByTagName, and iterating over these.
I am getting an "Uncaught TypeError: Cannot read property 'contains' of undefined" on the myFunc function.
I would be very happy if someone could point out my error.
<div id='button'></div>
<ul id='swatches'>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
The jQuery code
$('li').on('click', function(){
$('li').removeClass('selected');
$(this).toggleClass('selected');
});
Using the classList API
var swatch = document.getElementById('swatches'),
$li = document.querySelectorAll('#swatches li');
swatch.addEventListener('click', myFunc, false);
function myFunc(e){
var target = e.target;
for(var i=0; i<$li.length; i++){
if($li.classList.contains('selected')){
$li.classList.remove('selected');
}
}
if(target.nodeName.toLowerCase() === 'li'){
e.target.classList.toggle('selected');
}
}
I suspect the problem is how I am iterating over the node list returned from QuerySelectorAll.
Yes. You forget the indices. It should be
for (var i=0; i<$li.length; i++)
if ($li[i].classList.contains('selected'))
// ^^^
$li[i].classList.remove('selected');
// ^^^
However, two points:
You don't need to test for contains() before calling remove() unless you need the information explicitly. Trying to remove a class that doesn't exist just does nothing.
You might not need to iterate the whole $li collection on every click. Since there is only one <li> with the .selected class at a time, you might simply store a reference to the currently-selected element, or use
var cur = swatch.querySelector("li.selected");
if (cur) cur.classList.remove('selected');
(which could work with an id as well).
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/
I need to find a specific elements position in a jQuery collection.
For example in a collection of a elements I need to know the numeric position of the element with the "active" class.
<ul>
<li></li>
<li><a class="active" href="#"></a></li>
<li></li>
</ul>
I assumed using index would be the way to go but the following returns 0 no matter what the location of active.
$('ul li a').index('.active');
Is there any simple way to do what this?
Try this:
$('ul li a.active').index();
Note that even by using correct syntax this code always returns 0 as there is only one anchor link within li tags, you can find the index of parent li element instead.
$('ul li:has(a.active)').index();
Try:
$('ul li a').each(function(i) {
if ($(this).hasClass('active')) console.log(i);
});
jsFiddle example
Or
console.log ($('ul li:has(a.active)').index() );
This should do :
$('ul li a').index($('ul li a.active'));
If you pass a DOM element or jQuery object to index it returns the position of that element/object in the original collection.
jsfiddle for the sake of completeness
How about:
$('li').index($('.active').parent())
$("ul li a").each(function(i){
if($(this).hasClass("active")){
alert(i)
}
});
i hope it will solve your problem
Is it possible to select only direct descendants of an element using jQuery's find() or children() functions?
I have several ul elements, each with other ul elements inside them, and some root li elements too. I store a specific parent ul in a variable (as a jQuery object) and then look for any of the root li elements within using: my_root_ul.find('li');.
However, this method also finds any li that belongs to the ul inside the ul, if that makes sense.
My question is, how can I select only direct descendants of type li within the my_root_ul object using find(). Ordinarily, we could use something like $('ul > li') to return only direct li elements, but it must be possible to filter down the returned elements?
Here is an example to demonstrate what I mean:
<ul>
<li>I want this
<ul>
<li>I don't want this</li>
<li>I don't want this</li>
<li>I don't want this</li>
</ul>
</li>
<li>I want this</li>
<li>I want this</li>
</ul>
Like this:
my_root_ul.find('> li');
.children() also selects only the immediate children, so you can use that also:
my_root_ul.children('li');