Generated table with rowspan causing extra cells

独自空忆成欢 提交于 2020-02-28 15:41:04

问题


HTML

<table id="tableAppointment" bgcolor="#fcfcfc" border="1" cellspacing="1" width="100%">
 <thead>
  <tr>
   <td class="csstextheader" width="70px"></td>
   <td class="csstextheader" width="70px"><b>Time Slot&nbsp;</b></td>
   <td><b>Room 7</b></td>
   <td><b>Room 8</b></td>
   <td><b>Room 9</b></td>
   <td><b>Room 10</b></td>
  </tr>
 </thead>
 <tbody>
  <tr class="csstablelisttd">
   <td width="70px">08:00AM</td>
   <td>00</td>
   <td class="csstdred">John</td>
   <td>&nbsp;</td>
   <td>&nbsp;</td>
   <td>&nbsp;</td>
  </tr>
 </table> 

C#

private void GenerateTable() {
    for(int i = 0; i < tableAppointment.Rows.Count; i++) {
        foreach(DataRow dr in dataTableAcqModality.Rows) {
            cell = new HtmlTableCell() {
                InnerHtml = "&nbsp;"
            };
            cell.Style.Add("word-wrap", "break-word");
            cell.Attributes.Remove("class");
            cell.Attributes.Remove("rowspan");
            cell.Style.Remove("display");

            tableAppointment.Rows[i].Cells.Add(cell);
            tableAppointment.Style.Add("table-layout", "fixed");

            if(i == 0) {
                cell.Attributes.Add("ID", RoomID.ToString());
                cell.InnerHtml = String.Format(
                    "<span id='{0}'>{1}</span>",
                    RoomID, Roomname
                );
                tableAppointment.Rows[0].Attributes.Add("class", "csstextheader");
            }
        }
    }
}

protected void Page_Load(object sender, EventArgs e) {
    for(int i = 0; i < tableAppointment.Rows.Count; i++) {
        for(int j = 0; j < tableAppointment.Rows[i].Cells.Count; j++) {
            // This is where I need to remove the extra cells added 
            // after providing rowspan :(
        }
    }
}

In this JSBin, you can see the extra cells which get stuck on the right side of my rows due to rowspan being added to cells in the rows above. I'm trying to figure out how to remove these. Any suggestions are appreciated!


回答1:


Even though I don't know what you want, or have any idea why, I wrote some jQuery to remove the extra columns, because that's what we do here on StackOverflow.

I make no guarantees as to the efficiency or actual usefulness of this code.

$(document).ready(function() {
  $('table tr').each(function(i, v) {
    var cols = $(this).find('td');
    $(this).find('td[rowspan]').each(function() {
      var idx = $(this).index();
      console.log(idx);
      for(var j = 1; j < $(this).prop('rowspan'); j++) {
        $('table tr').eq(i+j).find('td').eq(idx).hide();
      }
    });
  });
});

Edit: Apparently you just need to give the rows a height to avoid that collapsing into each other behavior:

tr { height: 30px; }

Edit 2: I did update my jQuery to hide the cells immediately below a cell with a rowspan. It looks like you have conflicting appointments in your example. Joking aside, you probably want to deal with making sure there are no scheduling conflicts and not writing those extra cells in the first place.

A general strategy to deal with this ahead of time would be to initialize a multidimensional array of booleans (say cellsUsed) the same size as your table to false, then when printing a cell with having a rowspan, mark the rowspan - 1 array locations as true. Then when it's time to write a cell which corresponds to an array index set to true, you just don't output anything. If there happens to be an actual appointment defined in a cell you marked not to output, you have an entirely different problem, and have to deal with that.

EDIT: Here's a demonstration of why you have to hide the extra cells or go over the table twice to remove them in order to avoid errors:

Here's an example table where 'a' is a cell having rowspan > 1. an 'x' specifies the extra cells which need to be deleted, and a '-' signifies a blank which is intended to be blank.

This is the starting data in the table:

a-a-
x-xa
xaxx
-x-x

This is what happens if you start deleting from bottom left to top-right. After you delete the extra cell connected to the appointment in the second-to-last row you only have three cells in the last row. So when you traverse downward from the next appointment to delete fourth cell in that row, you get an error.

a-a-
x-xa
xaxx
--x!

If you try to delete from top-right to bottom left, when you go to delete the second appointment you end up erroneously deleting another appointment (The two 'a' stacked adjacently).

a-a-
-xa
axx
-x-x

The only way to avoid problems deleting the cells after generating the table is to mark all the cells you want deleted, then delete the cells in each row from right to left.




回答2:


To simplify it for you ..

If you use [rowspan="2"] in cell --> then you have to remove one cell from the next row

Example :

<table id="Table1" >
    <tr>
        <td rowspan="2" style="border-style:solid"></td>
        <td style="border-style:solid"></td>
    </tr>
    <tr>
        <td style="border-style:solid"></td>          
    </tr>
</table>

If you use [ rowspan="3" ] in cell --> then you have to remove one cell from the next two rows

Example :

<table id="Table1" >
    <tr>
        <td rowspan="3" style="border-style:solid"></td>
        <td style="border-style:solid"></td>
    </tr>
    <tr>
        <td style="border-style:solid"></td>          
    </tr>
    <tr>
        <td style="border-style:solid"></td>          
    </tr>
</table>



回答3:


Try something like this

protected void Page_Load(object sender, EventArgs e)
{
    for(int i = 0; i < tableAppointment.Rows.Count; i++)
    {
        for(int j = 0; j < tableAppointment.Rows[i].Cells.Count; j++)
        {
             // Assuming you have set the rowSpan by now.
             // TODO: Handle the possibility of missing rowspan attribute.
             int rowSpan = int.Parse(tableAppointment.Rows[i].Cells[j].Attributes["rowspan"]);
             if (rowSpan > 0) {
                // Now try to look ahead for rows and remove their j'th cell.
                for (int k = j+1; k < j + rowSpan; k++)
                {
                   tableAppointment.Rows[k].Cells.RemoveAt(j);
                   // TODO: Validate if k is not beyond available rows. It shoudn't be if rowspans are correct.
                }
             }
        }        //Here i have to remove those extra cell added after giving rowspan       
    }
}

NOTE: This code has not been tested, or even compiled. Provided more as a guidance.

Having said this I believe you can handle this better at the time of generating the table. If I understood correctly (may be I didn't) you have the table statically created, and then you inject the appointments. That is why you get this extra-cell syndrome. If you generate the entire table dynamically this should not happen to you.




回答4:


if your cells are blank then you can hide from css. like;

table{empty-cells:hide;}    



回答5:


I had to make assumptions since there is code missing: getting the data, what the data looks like, how the appointments are added to the table.

There are two things that I did to fix the issue. 1 - I switched the order of the loops, instead of looping through each room for a time span, I looped through all the time spans for one room before moving on the the next room. 2 - Because of change #1, I was able to increment the time span counter by the number of cells that needed to be removed (not recommended)

Default.aspx.cs

public partial class _Default : Page
{
  //Used to store generated data.
  List<Room> Rooms = new List<Room>();

  protected void Page_Load(object sender, EventArgs e)
  {
    if (!IsPostBack)
    {
      //To simulate the datasource
      GenerateData();

      //Generate the output
      GenerateTable();
    }
  }

  private void GenerateData()
  {
    //Generate Rooms
    foreach (var roomNumber in Enumerable.Range(7, 4))
    {
      var newRoom = new Room();

      newRoom.RoomID = roomNumber;
      newRoom.Roomname = "Room " + roomNumber.ToString();
      //Generate 40 15-minute time slot appointments for each room
      for (var count = 0; count < 40; ++count)
      {
        var newAppointment = new Appointment();

        newAppointment.Id = (roomNumber * 40) + count;
        newAppointment.Name = " ";
        newAppointment.NumberOfTimeSlots = 1;

        newRoom.Appointments.Add(newAppointment);
      }

      Rooms.Add(newRoom);
    }

    Rooms[0].Appointments[0].Name = "John";
    Rooms[0].Appointments[0].NumberOfTimeSlots = 1;

    Rooms[0].Appointments[2].Name = "John";
    Rooms[0].Appointments[2].NumberOfTimeSlots = 3;

    Rooms[1].Appointments[14].Name = "calc";
    Rooms[1].Appointments[14].NumberOfTimeSlots = 3;

    //More can be added
  }

  private void GenerateTable()
  {
    //Moved outside of the loop since it is globally setting the table and does not need to run for each row.
    tableAppointment.Style.Add("table-layout", "fixed");

    /**********************************************************************************************
     * Major change 1:
     * I flipped the order of the loops, I changed it from row->column to column->row.
     * What this allows you to do is skip the step of adding additional rows for the current room
     * by increment the row counter (not a good practice, need to refactor code).
     **********************************************************************************************/

    //You had: foreach(DataRow dr in dataTableAcqModality.Rows) {
    //I am assuming that this is a list of rooms to display
    foreach (var dr in Rooms)      
    {

      for (int i = 0; i < tableAppointment.Rows.Count; ++i)
      {
        var cell = new HtmlTableCell();

        cell.Style.Add("word-wrap", "break-word");
        cell.Attributes.Remove("class");
        cell.Attributes.Remove("rowspan");
        cell.Style.Remove("display");

        tableAppointment.Rows[i].Cells.Add(cell);

        if (i == 0) //Indicating the header row
        {
          cell.Attributes.Add("ID", dr.RoomID.ToString());
          cell.InnerHtml = String.Format(
              "<span id='{0}'>{1}</span>",
              dr.RoomID, dr.Roomname
          );
          tableAppointment.Rows[0].Attributes.Add("class", "csstextheader");
        }
        else
        {

          /***********************************************************************
           * Assumption that this is how you are adding the appointments to the 
           * table, did not see it in your quesiton
           ***********************************************************************/ 
          //i-1 to offset the header row
          cell.InnerHtml = dr.Appointments[i-1].Name;

          //NumberOfTimeSlots does not have to be part of the object, you are already doing it one way (not shown)
          cell.RowSpan = dr.Appointments[i - 1].NumberOfTimeSlots;

          //This is the inportant part, incrementing the row counter for this table by the number of cells you need to be removed becasue of the rowspan.
          //NOTE: I do not like the idea of messing with a loop counter, I would try to refactor your code, but since it was not provided this is a temporary fix.
          i += dr.Appointments[i - 1].NumberOfTimeSlots - 1;
        }
      }
    }
  }
}

public class Room
{
  public int RoomID { get; set; }
  public string Roomname { get; set; }
  public List<Appointment> Appointments { get; set; }

  public Room()
  {
    Appointments = new List<Appointment>();
  }
}

public class Appointment
{
  public int Id { get; set; }
  public string Name { get; set; }
  public int NumberOfTimeSlots { get; set; }
}

Default.aspx:

  Time Slot 08:00AM00  15  30  40

    <tr><td>09:00AM</td><td>00</td></tr>
    <tr><td>&nbsp;</td><td>15</td></tr>
    <tr><td>&nbsp;</td><td>30</td></tr>
    <tr><td>&nbsp;</td><td>40</td></tr>

    <tr><td>10:00AM</td><td>00</td></tr>
    <tr><td>&nbsp;</td><td>15</td></tr>
    <tr><td>&nbsp;</td><td>30</td></tr>
    <tr><td>&nbsp;</td><td>40</td></tr>

    <tr><td>11:00AM</td><td>00</td></tr>
    <tr><td>&nbsp;</td><td>15</td></tr>
    <tr><td>&nbsp;</td><td>30</td></tr>
    <tr><td>&nbsp;</td><td>40</td></tr>

    <tr><td>12:00PM</td><td>00</td></tr>
    <tr><td>&nbsp;</td><td>15</td></tr>
    <tr><td>&nbsp;</td><td>30</td></tr>
    <tr><td>&nbsp;</td><td>40</td></tr>

    <tr><td>01:00PM</td><td>00</td></tr>
    <tr><td>&nbsp;</td><td>15</td></tr>
    <tr><td>&nbsp;</td><td>30</td></tr>
    <tr><td>&nbsp;</td><td>40</td></tr>

    <tr><td>02:00PM</td><td>00</td></tr>
    <tr><td>&nbsp;</td><td>15</td></tr>
    <tr><td>&nbsp;</td><td>30</td></tr>
    <tr><td>&nbsp;</td><td>40</td></tr>

    <tr><td>03:00PM</td><td>00</td></tr>
    <tr><td>&nbsp;</td><td>15</td></tr>
    <tr><td>&nbsp;</td><td>30</td></tr>
    <tr><td>&nbsp;</td><td>40</td></tr>

    <tr><td>04:00PM</td><td>00</td></tr>
    <tr><td>&nbsp;</td><td>15</td></tr>
    <tr><td>&nbsp;</td><td>30</td></tr>
    <tr><td>&nbsp;</td><td>40</td></tr>

    <tr><td>05:00PM</td><td>00</td></tr>
    <tr><td>&nbsp;</td><td>15</td></tr>
    <tr><td>&nbsp;</td><td>30</td></tr>
    <tr><td>&nbsp;</td><td>40</td></tr>
  </tbody>
</table>


来源:https://stackoverflow.com/questions/13540806/generated-table-with-rowspan-causing-extra-cells

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!