user3143218
user3143218

Reputation: 1816

Check if current element is even or odd

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

Answers (3)

BoltClock
BoltClock

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

Bhojendra Rauniyar
Bhojendra Rauniyar

Reputation: 85575

Use modulo operator:

if ((i+1)%2==0) {
      console.log("even");
   }
   else {
      console.log("odd");
   }

Upvotes: -1

Victor Castillo Torres
Victor Castillo Torres

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

Related Questions