Reputation: 1816
Is there an easy way to check whether the current element in a nodeList is an even/odd child of its parent.
For example, if have a list of links.
<ul>
<li>Odd</li>
<li>Even</li>
<li>Odd</li>
<li>Even</li>
<li>Odd</li>
</ul>
And I iterate over a nodeList like this:
var links = document.querySelectorAll("ul li");
for (i = 0; i < links.length; i++) {
var link = links[i];
var parent = link.parentNode;
if (// this is an even link) {
console.log("even");
}
else {
console.log("odd");
}
}
How would I determine if the current link is even or odd?
I was thinking of selecting a new nodeList of all the parent's odd li
elements using li:nth-child(odd)
on the parent and then checking whether the current node is in that nodeList. Although I'm not sure how to do that exactly.
How can I check whether the current node is even/odd in relation to its parent?
Upvotes: 2
Views: 3914
Reputation: 724102
This question is similar to Get an element's nth-child number in pure JavaScript
How can I check whether the current node is even/odd in relation to its parent?
The problem with simply incrementing i
on every iteration, as all the other answers are doing, is that this calculation makes no relation to the parent node whatsoever. If you notice, none of the existing answers make use of link.parentNode
at all!
Since the calculation isn't aware of the context of the parent node, it basically assumes there is exactly one ul
element and all li
elements are children of that one ul
in order to work correctly. The moment you have nested ul
elements or even just multiple ul
elements in the same document, it will break.
Note that the problem is not with the %
line. In fact, that is exactly how you determine if an integer is even or odd. The problem is that the index isn't being calculated in relation to the parent node.
For example, if I modify your list to include a nested ul
with exactly one li
:
<ul>
<li>Odd
<ul>
<li>Odd</li>
</ul>
</li>
<li>Even</li>
<li>Odd</li>
<li>Even</li>
<li>Odd</li>
</ul>
The output will be all wrong once it counts the inner li
(the second line):
[12:07:25.505] odd [12:07:25.505] even [12:07:25.505] odd [12:07:25.505] even [12:07:25.506] odd [12:07:25.506] even
I wrote a script in an answer to the similar question I linked to above. Here's a quote:
One way to achieve this that is more foolproof is to loop through the child nodes of each element's parent node, incrementing a counter for each child node that is an element node (since
:nth-child()
only counts element nodes):
And here's the script, adapted for your use case:
var links = document.querySelectorAll("ul li");
for (var i = 0; i < links.length; i++) {
var link = links[i];
var parent = link.parentNode;
var child = parent.firstChild;
var index = 0;
while (true) {
if (child.nodeType === Node.ELEMENT_NODE) {
index++;
}
if (child === link || !child.nextSibling) {
break;
}
child = child.nextSibling;
}
if (index % 2 == 0) {
console.log("even");
}
else {
console.log("odd");
}
}
Now the output will be correct:
[12:35:22.273] odd [12:35:22.273] odd [12:35:22.273] even [12:35:22.273] odd [12:35:22.273] even [12:35:22.273] odd
Again, the second line represents the inner li
, which in the modified HTML is the first (and therefore odd) child of its parent ul
.
Upvotes: 4
Reputation: 85575
Use modulo operator:
if ((i+1)%2==0) {
console.log("even");
}
else {
console.log("odd");
}
Upvotes: -1
Reputation: 10811
Just check whether i+1
is even or odd
for (i = 0; i < links.length; i++) {
var link = links[i];
var parent = link.parentNode;
if ((i+1)%2 == 0) {
console.log("even");
}
else {
console.log("odd");
}
}
Upvotes: 1