Question

Consider the following table:

<table>
    <thead>
        <tr>
            <th scope="col" />
            <th scope="col">A</th>
            <th scope="col">B</th>
            <th scope="col">C</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th scope="row">1</th>
            <td>Apples</td>
            <td>Oranges</td>
            <td>Pears</td>
        </tr>
        <tr>
            <th scope="row">2</th>
            <td rowspan="2">Subcategory Heading</td>
            <td>ASP.Net</td>
            <td>Other</td>
        </tr>
        <tr>
            <th scope="row">3</th>
            <td>MVC</td>
            <td>PHP</td>
        </tr>
        <tr>
            <th scope="row">4</th>
            <td>Red</td>
            <td>Green</td>
            <td>Blue</td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
            <td colspan="4">Some pointless footer content</td>
        </tr>
    </tfoot>
</table>

How would I retrieve the correct column number for the cell containing the text "MVC" or "PHP" using jQuery? The correct answer would be column 3, but just using .prevAll().length will only count the number of previous cells, which will not accurately reflect their actual column position in this case?

I'm sure I'll need to use each(), but I'm looking for the most efficient implementation as well.

Was it helpful?

Solution

Something like this?

<!doctype html>
<table id="foo">
    <thead>
        <tr>
            <th scope="col" />
            <th scope="col">A</th>
            <th scope="col">B</th>
            <th scope="col">C</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th scope="row">1</th>
            <td>Apples</td>
            <td>Oranges</td>
            <td>Pears</td>
        </tr>
        <tr>
            <th scope="row">2</th>
            <td rowspan="2">Subcategory Heading</td>
            <td>ASP.Net</td>
            <td>Other</td>
        </tr>
        <tr>
            <th scope="row">3</th>
            <td>MVC</td>
            <td>PHP</td>
        </tr>
        <tr>
            <th scope="row">4</th>
            <td>Red</td>
            <td>Green</td>
            <td>Blue</td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
            <td colspan="4">Some pointless footer content</td>
        </tr>
    </tfoot>
</table>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
<script>
    var table = $('table#foo');
    table.find('td[rowspan], th[rowspan]').each(function() {
    var cellNum,
        reference = this,
        columnNum = $(this).attr('rowspan'),
        parentTr = $(this).closest('tr'),
        parentTrs = $(this).closest('tr').parent().find('tr');

    parentTr.find('>td, >th').each(function(i,o) {
        if ( this == reference ) {
        cellNum = i;

        var counter = columnNum;

        while ( counter-- ) {
            $(this).closest('tr').next().find('>td,>th').each(function(i,o) {
            if ( cellNum == i ) {
                $(this).addClass('rowspan-affected');
                $(this).attr('colNum', columnNum);
            }
            });
        }
        }
    });

    /* testing
    window.num = num;
    window.parentTr = parentTr;
    window.parentTrs = parentTrs;
    */
    });
</script>

OTHER TIPS

I recently wrote a solution for this situation for the same problem:

How can I find each table cell's "visual location" using jQuery?

Might be another solution for people searching for this.

Well, the shortest (over)simplification is:

var theCell = $('td:contains("MVC")');
col = theCell.parent().children().index(theCell);
row = theCell.parent().parent().children().index(theCell.parent());

Note, the indexes returned are zero-based. Basically, first you find the cell of interest. For the column, you go up a level in the DOM to the <tr>, get all children (which in this case will be the descendant <td>s and the <th>s) and find the position of the element of interest in that set. For the row, you climb up to, in this case, the <tbody>, get all rows, and find the position of the row of the <td> of interest.

As you can imagine, changes in the structure of the table changes the possible results. However, if you programmatically use the indexes later the same way you got them, you can get back to the same cell. I bring this up because if you somehow use the indexes visually in the UI, you may have to get trickier and account for spans, <tbody> vs no <tbody>, etc...

Don't know if it is more efficient than meder's answer. But, it is definitely much more maintainable! :)

I think the closest to shorten search steps would do something like this:

var counter = 0;
$("#idTable tbody tr").each(function(){

   var html = $(this).html();
   var php = html.indexOf("PHP") > -1 ? true : false;
   var mvc = html.indexOf("MVC") > -1 ? true : false;

   if(php || mvc) {
       $(this).find("td").each(function(){ counter += (($(this).html()=="PHP") || ($(this).html()=="MVC")) ? 1 : 0; });
   }

});

Try something like this, you get the point. It works, so why not :)

.stuffing {
    display: none;
}
<table>
    <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
        <td>4</td>
    </tr>
    <tr>
        <td colspan="3">1</td>
        <td class="stuffing"></td>
        <td class="stuffing"></td>
        <td>4</td>
    </tr>
</table>
var tb= document.querySelector('table');
tb.rows[0].cells[3].innerHTML;  //4
tb.rows[1].cells[3].innerHTML;  //4

Give kudos to this guy for his answer on my quesiton.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top