tags:

views:

78

answers:

4

I can't quite wrap my head around this one...

A table like the one below is spit out by a renderer from some XML. The XML it comes from has a variable depth. (Please point out if I'm using the rowspans in a horrific manner as well, I just came to this table with some experimentation).

<table border="1">
    <tr>
        <td rowspan="12">> 1</td>
    </tr>
    <tr>
        <td rowspan="3">1 > 2</td>
    </tr>
    <tr>
        <td>1 > 2 > 5</td>
    </tr>
    <tr>
        <td>1 > 2 > 6</td>
    </tr>
    <tr>
        <td rowspan="3">1 > 3</td>
    </tr>
    <tr>
        <td>1 > 3 > 7</td>
    </tr>
    <tr>
        <td>1 > 3 > 8</td>
    </tr>
    <tr>
        <td rowspan="3">1 > 4</td>
    </tr>
    <tr>
        <td>1 > 4 > 9</td>
    </tr>
    <tr>
        <td>1 > 4 > 10</td>
    </tr>
</table>

![alt text][1]

What I'm trying to accomplish in JQuery is this...

  1. User clicks cell "1 > 2" (which will have an ID).
  2. An item is dynamically added to the third level, but UNDER "1 > 2 > 6".

What I could do is just add another row underneath "1 > 2" and increase the rowspan from "1 > 2", but the new cell would then appear out of order amongst "1 > 2 > 5" and "1 > 2 > 6".

I don't really need the exact code to do this, just something to stop my head from spinning around this...Thanks!

A: 

If I were you, I would use nested lists and use CSS to handle your indentation. Tables are not the answer.

<ul><li>1
    <ul><li> > 2 </li></ul>
</li></ul>
Diodeus
I would definitely prefer UL's for this, but unfortunately some compliance issues ruled them out for this solution.
Ocelot20
A: 

Hey BPotocki,

Im not exactly sure what you are looking for but I believe you need something like this

$('#myRow').click(function() {
    $(this).parent.next().next().find('td').html('ADD ITEM HERE');
}

This would basically get the sibling that is 2 rows past the current row that was clicked. I hope this is what you mean by "third level".

Hope this helps, Metropolis

EDIT

Ok I think I see what you are trying to do now. The "third level" is basically going to be all rows after the clicked row that do not contain a particular rowspans/class/id.

Heres what I think you should do. Give your root elements an onclick event with id's of something like "root1, root2, root3...etc..." Then, give all rows after that one but before the next "root level row" a class of "siblingroot1, siblingroot2, siblingroot3....etc...", once that is setup, then you can create a click event like so,

$('#rootEle').click(function() {
    $('.sibling' + $(this).attr('id')).find('td').html('ADD ITEM');
}
Metropolis
There's a varying number of elements and levels ("Depth" in node/tree terms I believe) so unfortunately I can't just hardcode how many rows to pass.
Ocelot20
Ok im confused now. Is every row that has <td rowspan="3">1 > 4</td> considered a "root" level row? And you want to go 3 levels after that? If all of the markup rows are siblings, how can you tell what the "third" level is?
Metropolis
A: 

Let me see if I can get my head around this in pseudocode. Seems you need to do two quite distinct things:

this.parent.rowspan +1

and

this.parent.find.nextsibling.notWithRowSpan.addnewRowAndCell

graphicdivine
+2  A: 

It seems your rowspans are a little strange, the first row of the table makes sense to have 3 cells in it, the first rowspan of 6, the second a rowspan of 2, and finally the "single cell"...

Sadly, <tr>'s and <td>'s are unreliable when dealing with colspan/rowspan issues across browsers. SO1303106 shows a solution that builds up a matrix of each row/column and creates some functions to help you query it. This article inspired that solution, and shows the problem.

Using the getTableState() function from that other article. you could do something like this:

$("table").click(function(e) {
  var targ = $(e.target);
  var c = targ.closest('td').get(0);
  if (!c) return;
  var state = getTableState($(this).closest('table')[0]);
  var rowSpan = c.rowSpan || 1;
  // get the "bottom row" number from our clicked cell:
  var rowNum = $(c).closest('tr').get(0).rowIndex + (rowSpan - 1);
  var column = state.getRealColFromElement(c);
  // push all rowspans on the clicked td and anything to the left
  for (;column>=0; column--) {
    var cell = state.cellMatrix[rowNum][column].cell;
    cell.rowSpan = (cell.rowSpan||1)+1;
  }
  // insert a new row after the "bottom row"
  $(this).closest('table').find('tr').eq(rowNum).after(
     '<tr><td>'+$(c).text() + ' > new</td></tr>'
  );
});

And just to put it all together a jsbin preview of the finished product...

gnarf
Thanks! A bit complicated but accomplishes exactly what I'm looking for.
Ocelot20