Search code examples
htmlasp.net-mvc-5webgridwcag2.0

ASP.net webgrid generate tfoot after tbody in html


I have a legacy application I've picked up and have a requirement to pass html5 validation and WCAG2.0 AA tests. I'm running into an issue with the System.Web.Helpers.Webgrid and the table it generates as the tfoot element is being generated before the tbody element which causes it to fail validation. Obviously this was fine years ago, but with the new validation rules, having a tfoot ahead of the tbody is no longer allowed.

Is there a way to force the webgrid to generate the tfoot element after the tbody element or some kind of easy workaround? Simply disabling the footer (no paging) isn't an option as sometimes the data returned will have hundreds of rows.

Code for generating table:

var grid = new WebGrid(source: Model.Stuff,
                       defaultSort: "Stamp",
                       rowsPerPage: 20,
                       fieldNamePrefix: "wg_",
                       canPage: true,
                       canSort: true,
                       pageFieldName: "pg");
<text>
@grid.GetHtml(tableStyle: "gridtable",
                headerStyle: "gridtableheading",
                rowStyle: "gridtablerow",
                alternatingRowStyle: "gridtablerowalternate",
                columns:
                    grid.Columns(
                                grid.Column("View", format: (item) => (Html.ActionLink("Select", "View", "Item", new { itemID = item.ID }, null)), style: "padtable centeralign"),
                                grid.Column("ID", "ID", style: "padtable rightalign"),
                                grid.Column("CreatedDate", "Stamp", format: (item) => String.Format("{0:MM/dd/yyyy hh:mm tt}", item.CreatedDate), style: "padtable leftalign"),
                                grid.Column("Type", "Type", style: "padtable rightalign"),
                                grid.Column("Status", "Status", style: "padtable leftalign"),
                     ), mode: WebGridPagerModes.Numeric)
</text>

Here's a generalized version of what that actually generates

<!DOCTYPE html>
<html lang="en-US">
<head>
  <title>Table Test</title>
</head>
<body>
  <table>
    <thead>
      <tr>
        <td>header1</td>
        <td>header2</td>
      </tr>
    </thead>
    <tfoot>
      <tr>
        <td>Previous page link</td>
        <td>Next page link</td>
      </tr>
    </tfoot>
    <tbody>
      <tr>
        <td>table row1 data 1</td>
        <td>table row1 data 2</td>
      </tr>
      <tr>
        <td>table row2 data 1</td>
        <td>table row2 data 2</td>
      </tr>
    </tbody>
  </table>
</body>


Solution

  • I wasn't able to find a way to do this automatically, however the idea of customizing the footer mentioned by slugolicious made me realize that it was likely just easier to edit the HTML to move the footer.

    This is far from a generalized solution, but it easily moves the footer to the bottom of the table for the cases I need to solve.

    string TableHTML = grid.GetHtml(tableStyle: "gridtable",
                headerStyle: "gridtableheading",
                rowStyle: "gridtablerow",
                alternatingRowStyle: "gridtablerowalternate",
                columns:
                    grid.Columns(
                                grid.Column("View", format: (item) => (Html.ActionLink("Select", "View", "Item", new { itemID = item.ID }, null)), style: "padtable centeralign"),
                                grid.Column("ID", "ID", style: "padtable rightalign"),
                                grid.Column("CreatedDate", "Stamp", format: (item) => String.Format("{0:MM/dd/yyyy hh:mm tt}", item.CreatedDate), style: "padtable leftalign"),
                                grid.Column("Type", "Type", style: "padtable rightalign"),
                                grid.Column("Status", "Status", style: "padtable leftalign"),
                     ), mode: WebGridPagerModes.Numeric).ToHtmlString();
    
    
    string TableFooter = TableHTML.Substring(TableHTML.IndexOf("<tfoot>"),TableHTML.IndexOf("</tfoot>") + 8 - TableHTML.IndexOf("<tfoot>")); //Grab the HTML for the footer
    string NewTable = TableHTML.Substring(0, TableHTML.IndexOf("<tfoot>")); //Take the HTML up until the footer
    NewTable += TableHTML.Substring(TableHTML.IndexOf("</tfoot>") + 8).Replace("</table>","");  //Omit the footer, grab the rest of the HTML, remove the closing tag
    NewTable += TableFooter; //Reinsert the footer at the end
    NewTable += "</table>"; //Add the closing tag
    
    <text>
        @(new HtmlString(NewTable))
    </text>