DOM Targeting all td's under a certain td in vanilla JavaScript

How to target all td’s under the td with the innerText of “date”, in this table?

Edit: I don’t have control of the actual site from which I copied the HTML so I need an automatic way to select these without adding a class to them (as optional in codepen).


I know how to check individual elements with document.querySelector (or lists like ul & li’s with document.querySelectorAll.forEach() ) but I don’t have the slightest idea how to target all td’s under a certain td.

I believe I will learn from an answer as I keep learning the language in my formal studies. None of my courses or articles so far dealt with grouping td’s in tables without these, especially not when these don’t have specific identifiers as in this case.

In this case, non of the children under the cell with the innerText of “date” seems grouped to me.

Give them all the same class (e.g. class="dateCell"), then use this to select them all

var dateCells = document.getElementsByClassName("dateCell");

But how will you select them if they are td like any other and has no unique way to be found (besides maybe with targeting general date format with regex, and I’ve yet to learn regex as I’m just in basic courses).

Just give the <td>'s you’re interested in the class I showed you above - it should appear only in one <td> per row, like this…

<tr>
  <td>Some other cell</td>
  <td>Some other cell</td>
  <td class="dateCell">Your date goes here</td>
  <td>Some other cell</td>
  <td>Some other cell</td>
</tr>

Oh, sorry for not mentioning, I don’t have control of the actual site from which I copied the HTML so this solution can’t serve me.

You’d first need to find the child-index of that table element, and could then use the nth-child selector to get all elements in the same column:

// Get all table elements on the page (should be more specific
// if the table in question has an unique identifier)
const allTds = document.querySelectorAll('td')

// Find the td element that contains the text "date"
const dateTd = Array.from(allTds).find(td => td.textContent === 'date')

// Get the index of that element with respect to its siblings
const childIndex = Array.from(dateTd.parentNode.children).indexOf(dateTd)

// Get all td elements in the same table that have the same child index
const column = dateTd.closest('table').querySelectorAll(`td:nth-child(${childIndex})`)
2 Likes

Thank you dearly @m3g4p0p. Do you have some more spare time to take a look at the pen? The example didn’t work for me probably because I don’t use it right. I try to base a class on it and change the style through that class.

column would be a NodeList here, so you can’t just add a class to it – you’ll have to iterate over the elements:

column.forEach(td => td.classList.add("dateItem"))

Oh BTW, it just occurred to me that nth-child isn’t zero-indexed, so we’ll have to add one to childIndex for it to work as expected.

Thanks. Regarding adding 1, I tried:

const childIndex = Array.from(dateTd.parentNode.children).indexOf(dateTd) + 1;

Or:

const column = dateTd.closest(“table”).querySelectorAll(td:nth-child(${childIndex}) +1);

These didn’t cause a change.

In your pen you’re getting an

Uncaught ReferenceError: td is not defined

which is caused by this line

const dateTd = Array.from(allTds).find(td.textContent === "date");

Also, the find() method expects a function as its argument – have a closer look at the code I posted above.

Hmm, I fixed the issue with the uncaught reference error. Regarding the find() method. AFAIU, the td is it’s (arrow) function as an argument because it’s inside her parenthesis. Maybe I miss your point here.

In the original site (doesn’t work in codepen due to lack of CSS identifiers there), this code worked just fine:

let table = document.querySelector( "table.MOallTable tbody" );

let fifthColumn = table.querySelectorAll( "tr + tr td:nth-child(5)");

fifthColumn.forEach((element) => {
    element.style.display = "none";
});

// display: none given just as example.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.