Development

Working With Tables in jQuery

Possibly one of the most frustrating or confusing tasks a developer may find is retrieving information from within a table.  Getting references to cells, rows and columns often seems like it should be a doddle with jQuery, but getting just the right combination of selectors and commands can sometimes be more elusive than it would seem at first blush.

Let’s have a look at how to get the right information from your tables first time, every time.

Basic Tasks

Typically, your most basic tasks are going to be finding the column or row number of a given cell.  Assuming you’re only interested in <td> tags, your code would look like this:
Row:

Column:

Simple.  But what does that prevAll() thing do again?  To quote directly from the documentation, it finds “all sibling elements in front of the current element”.  All I have to do is count how many there are and suddenly I have my rank and file position.

The tricky thing about tables is the number of nested elements.  Tables can have anywhere between one and five child elements (you are marking your tables up semantically, aren’t you?), which in turn can have any number of rows, columns and cells.  Traversing a table is almost like a DOM in its own right.  The trick is to think very analytically and carefully about your jQuery selectors and what elements you’re telling it to work with.

But what about “merged” cells and columns (i.e. cells with a “rowspan” or “colspan” property)?  What impact does this have on our ability to quickly find the index?

Working With Spanned Cells

Spanned cells add quite a bit more complexity to traversing a table.  I can’t just get the number of previous cells or rows to find my position because the number returned won’t reflect my cell’s actual place in the overall table structure.

The colspan problem is the easiest to solve.  Using the prevAll() function above, we can do some simple arithmetic to factor in the value of any colspan attributes assigned against a table cell.  So if I have 3 table cells, but one of those has a colspan of 2, then I know that my actual column index is 4 (three cells: one spanning two columns and two spanning one each – 2+1+1).

Here’s the code (snippet):

What we’re doing is getting our row number, then setting up a variable to hold our column index. We then need to iterate over each cell and check to see if it has a “colspan” attribute. If it does, we’ll add its value to our column count, otherwise we’ll just add 1 to our column count.

The rowspan attribute is the hardest to solve.  Given a clicked cell, we have to work out whether its predecessor cells are affected by a rowspan and, if so, in which row that rowspanned column starts.  I’ve struggled to find a suitable and efficient approach to this, although the lazy option is to count the number of columns in the thead element and then work out the position of the target from how many cells appear before and after.  Not pretty, but can be a viable solution if you’ve marked your table up semantically.  Since this post is already more than a week late, I’m going to go cap-in-hand to the community and see if someone else has a good, robust approach. I’ll update this post soon when I find a best approach (suggestions welcome).

A working demo of all these cases can be found on my demos site.

You can also download the demo to have a play with some of the source.  jQueryIntersection_Demo

3 Comments

  1. Tim

    Hi Phil

    Are you able to share your solution on calculating the row number whilst still considering the rowspan attribute?

    Cheers
    Tim

  2. Rahul

    Hi Phil,

    Did you come across a clean way to handle the rowspans after writing this post ?

  3. Tim

    Hey Rahul

    I got a good solution to this on Stack Overflow: How can I find each table cell’s “visual location” using jQuery?.

    Cheers
    Tim

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">