0

Basically the same question as How can I get the corresponding table header (th) from a table cell (td)? but not jQuery specific.

From a given <td> is there an easy way to find the corresponding <th>?

    <table width="100%" id="stock">
        <tr>
            <th>Name</th>
            <th>Type</th>
            <th>Quantity</th>
            <th>Options</th>
        </tr>
        <tr>
            <td>foo</td>
            <td id="target">bar</td>
            <td>-1</td>
            <td>...</td>
        </tr>

I'd like something doing this:

 document.getElementById('target').correspondingTH // would return HTMLObject <th>Type</th>

An ideal answer might contain both a jQuery way to do it and a vanilla one but I'm personally looking for a vanilla one.

Community
  • 1
  • 1
jeromej
  • 10,508
  • 2
  • 43
  • 62
  • I wasn't sure how to deal with this situation as this will likely create "some kind" of duplicates. – jeromej May 19 '16 at 00:57
  • `td.parentNode` refers to its owning ``. Your question is nonsense because `td` are not descendents of `th`. Did you mean find the first `th` on the same row as the `td`? – doug65536 May 19 '16 at 01:01
  • @doug65536 No vanilla (without Javascript) solution. – jeromej May 19 '16 at 01:04
  • 1
    "Your question is nonsense..." He never mentioned anything about `th` being the parent of a `td`. However, please be more specific in defining "corresponding" please. – theblindprophet May 19 '16 at 01:05
  • Yeah, sorry I didn't make it clear, I meant, there is no link or relationship between `th` and `td`. Nonsense was the wrong word. Nonexistent relationship would be more accurate. At best you can infer that a given `th` is related to a `td` that happens to be on the same row. – doug65536 May 19 '16 at 01:06
  • @doug65536 I think he means the `` that contains the column heading for the ``. So if he has the 4th `` in a row, he wants the 4th `` in the header row. – Barmar May 19 '16 at 01:08
  • @theblindprophet I added an, hopefully clear, example. – jeromej May 19 '16 at 01:09
  • But could refer to a `th` at the left end of each row. – doug65536 May 19 '16 at 01:09
  • @doug65536 Right, if the table would have been "vertical" or "double entry"-like. I didn't think about that. Currently I only need the corresponding `` into a "classical" "horizontal" table. (but that would be definitely interesting too) – jeromej May 19 '16 at 01:12
  • http://stackoverflow.com/questions/5913927/get-child-node-index shows how to get the index of an element in its parent using plain JS. You can then use that index with `document.querySelector` to find the `` with the same index. The linked question shows how to create the selector (they're the same as for jQuery). – Barmar May 19 '16 at 01:12
  • The whole thing is a duplicate in a way. A pure js version should go in the linked question, right? Unless we can tag this one as pure js somehow to differentiate them. – doug65536 May 19 '16 at 01:15
  • @Barmar Yep it is. Working on it. Will share if I come up with something neat. I was kinda hoping there'd be something I wouldn't know about. – jeromej May 19 '16 at 01:16
  • @doug65536 Right, I didn't how to go and ask for a non-jQuery in that question thread. Would adding an answer with only the non-jQuery in the other thread ok? – jeromej May 19 '16 at 01:18
  • 1
    So, you want to find the Nth `th` in the first row of the table, given the Nth `td` on a row? – doug65536 May 19 '16 at 01:18
  • Maybe this could work, too: https://jsfiddle.net/r972coje/3/ :) – sinisake May 19 '16 at 01:22
  • @nevermind Using `offsetLeft` is surprising. Is that reliable? I'm gonna post my version and probably delete my question. – jeromej May 19 '16 at 01:30
  • If you want to sidestep issues with `colspan`, try to use the position of the left edge of the element to match up the `th` with the `td`. Then, colspan will not break the algorithm. – doug65536 May 19 '16 at 01:57
  • @doug65536 http://stackoverflow.com/a/37312707/1524913 It doesn't handle the possible `colspan` issue though – jeromej May 19 '16 at 02:01
  • 1
    @JeromeJ I added [an answer](http://stackoverflow.com/a/37312894/1127972) there. – doug65536 May 19 '16 at 03:18

3 Answers3

1

I think you need to step through the TH colSpans to exactly match the TD

Try

function getHeadCell(td) {
  var index = Array.prototype.indexOf.call(td.parentNode.children, td);

  var table = td;
  while (table && table.tagName != 'TABLE') table = table.parentNode;

  var cx = 0;
  for (var c = 0; cx <= index; c++) cx += table.rows[0].cells[c].colSpan;

  return table.rows[0].cells[c - 1];
}

See https://jsfiddle.net/Abeeee/upt75s2x/34/ for a working example

user1432181
  • 918
  • 1
  • 9
  • 24
0

Pure JavaScript's answer.

var index = Array.prototype.indexOf.call(your_td.parentNode.children, your_td)
var corresponding_th = document.querySelector('#your_table_id th:nth-child(' + (index+1) + ')')

As posted here in the more jQuery specifc question: https://stackoverflow.com/a/37312707/1524913

Community
  • 1
  • 1
jeromej
  • 10,508
  • 2
  • 43
  • 62
0

HTML table model gives easier solution. jquery in this case is more sophisticated. I tested following table:

<table style="width:100%" id="stock">
    <tbody>
        <tr>
            <td>foo</td>
            <td id="target">bar</td>
            <td>-1</td>
            <td>...</td>
        </tr>
        <tr>
            <td>foo</td>
            <td id="target">bar</td>
            <td>-1</td>
            <td>...</td>
        </tr>
    </tbody>
    <tr>
        <td>foo</td>
        <td id="target">bar</td>
        <td colspan="2">-1</td>
        <!--<td>...</td>-->
    </tr>
    <thead>
        <tr>
            <th>Name</th>
            <th>Type</th>
            <th>Quantity</th>
            <th>Options</th>
        </tr>
    </thead>
    </table>

Script without jquery is simple and straightforward.

    window.onload = function () {
        var tbl = document.getElementById('stock');
        var tds = document.getElementsByTagName('td');
        for (var i = 0, td; td = tds[i]; ++i) {
            td.onclick = function () {
                var tr = this.parentNode;
                console.log(tbl.rows[0].cells[this.cellIndex].innerHTML);
            }
        }
    }

jquery also is useful.

    $(document).ready(function () {
        $('#stock td').click(function () {

            console.log($(this).parents('table').find('tr:first-child').children('th:nth-child(' + (this.cellIndex + 1) + ')').html());
        });
    });

<thead> can be placed at the top, at the bottom, and between rows. thead inside tbody is obvious error but browser fixes it. Scripts work in any case.

Alex Kudryashev
  • 9,120
  • 3
  • 27
  • 36
  • `rows` always list the `thead` rows first?? Tha'ts neat! Also, why no one has told me about `cellIndex`? :D – jeromej May 19 '16 at 05:11
  • Yes, exactly. "Also, why no one has told me about cellIndex?" - no answer. – Alex Kudryashev May 19 '16 at 05:12
  • If you add `thead` element (with rows inside) then browser puts it on top and repeats on every printed page. `tfoot` goes to the bottom. If you don't explicitly add `tbody` browser does it for you. There can be 1 thead, 1 tfoot and as many tbody's as you want. – Alex Kudryashev May 19 '16 at 05:34
  • 1
    Note `cells` and `cellIndex` do not take colspan into account. – Oriol May 19 '16 at 18:30