【问题标题】:Create a HTML table where each TR is a FORM创建一个 HTML 表,其中每个 TR 是一个 FORM
【发布时间】:2011-05-01 11:03:54
【问题描述】:

我正在尝试创建一个表格,其中每一行都是一个表格。我希望每个输入都在不同的表分区中,但我仍然需要,例如,所有第一个输入都属于同一个表头,依此类推。

我想做的是一个可编辑的网格,或多或少是这样的:

<table>
    <tr>
        <form method="POST" action="whatever">
            <td><input type="text"/></td>
            <td><input type="text"/></td>
        </form>
    </tr>
    <tr>
        <form method="POST" action="whatever">
            <td><input type="text"/></td>
            <td><input type="text"/></td>
        </form>
    </tr>
</table>

但显然我不能以这种方式排列标签(或者 w3c 验证器所说的)。

有什么好的方法吗?

【问题讨论】:

标签: html webforms html-table web-standards


【解决方案1】:

如果您想要一个“可编辑网格”,即允许您将任何行设为表单的表格结构,请使用模仿 TABLE 标签布局的 CSS:display:tabledisplay:table-rowdisplay:table-cell

无需将整个表格包装在一个表格中,也无需为表格的每个明显行创建单独的表格和表格。

试试这个:

<style>
DIV.table 
{
    display:table;
}
FORM.tr, DIV.tr
{
    display:table-row;
}
SPAN.td
{
    display:table-cell;
}
</style>
...
<div class="table">
    <form class="tr" method="post" action="blah.html">
        <span class="td"><input type="text"/></span>
        <span class="td"><input type="text"/></span>
    </form>
    <div class="tr">
        <span class="td">(cell data)</span>
        <span class="td">(cell data)</span>
    </div>
    ...
</div>

将整个 TABLE 包装在 FORM 中的问题在于,任何和所有表单元素都将在提交时发送(也许这是需要的,但可能不是)。此方法允许您为每个“行”定义一个表单,并在提交时仅发送该行数据。

将 FORM 标记包裹在 TR 标记(或 TR 包裹在 FORM)周围的问题在于它是无效的 HTML。 FORM 仍然允许像往常一样提交,但此时 DOM 已损坏。注意:尝试使用 JavaScript 获取 FORM 或 TR 的子元素,这可能会导致意外结果。

请注意,IE7 不支持这些 CSS 表格样式,IE8 需要一个 doctype 声明才能使其进入“标准”模式:(试试这个或等效的)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

任何其他支持 display:table、display:table-row 和 display:table-cell 的浏览器都应该像使用 TABLE、TR 和 TD 标签一样显示您的 css 数据表。他们中的大多数人都这样做。

请注意,您还可以通过分别使用 display: table-header-grouptable-row-grouptable-footer-group 将行组包装在另一个 DIV 中来模仿 THEAD、TBODY、TFOOT。

注意:你唯一不能用这个方法做的是colspan。

看看这个插图:http://jsfiddle.net/ZRQPP/

【讨论】:

    【解决方案2】:

    如果所有这些行都是相关的,并且您需要更改表格数据...为什么不将整个表格包装在一个表单中,并将 GET 更改为 POST(除非您知道您不是将发送超过GET 请求可以发送的最大数据量)。

    (这是假设,当然,所有的数据都去同一个地方。)

    <form method="POST" action="your_action">
    <table>
    <tr>
    <td><input type="text" name="r1c1" value="" /></td>
    <!-- ... snip ... -->
    </tr>
    <!-- ... repeat as needed ... -->
    </table>
    </form>
    

    【讨论】:

    • 这可能是最好的解决方案。
    • 如果我理解正确,您正在尝试创建一个数据网格,既可以显示现有数据,也可以启用编辑/数据输入。最好的办法是使用 javascript 来创建和构建这个数据网格——那里有 很多 好的。
    【解决方案3】:

    您可能对列宽有疑问,但您可以明确设置。

    <table>
      <tr>
        <td>
           <form>
             <table>
               <tr>
                 <td></td> 
                 <td></td> 
                 <td></td> 
                 <td></td> 
                 <td></td> 
                 <td></td> 
               </tr>
             </table>
           </form>
         </td>
        </tr>
      <tr>
        <td>
           <form>
             <table>
               <tr>
                 <td></td> 
                 <td></td> 
                 <td></td> 
                 <td></td> 
                 <td></td> 
                 <td></td> 
               </tr>
             </table>
           </form>
         </td>
        </tr>
      </table>
    

    您可能还想考虑将其制作为单个表单,然后使用 jQuery 从您想要的行中选择表单元素,将它们序列化,然后将它们作为表单提交。

    见:http://api.jquery.com/serialize/

    此外,还有许多非常不错的网格插件: http://www.google.com/search?q=jquery+grid&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a

    【讨论】:

    • 肯定回答了这个问题 - 但该死的太丑了:)
    • 是的,这个问题很可能是做错事的征兆,但似乎我们应该回答这个问题,除了苦苦挣扎。
    • -1 用于向某人展示如何甚至错误地做某事。
    • 其实,这个是有效的标记,就像我不会使用它一样。
    • 有效,但在大多数情况下可能不可接受。当你这样包装它时,你所有的列都会失去它们的对齐方式。
    【解决方案4】:

    如果使用 JavaScript 是一种选择,并且您想避免嵌套表,请包含 jQuery 并尝试以下方法。

    首先,您必须为每一行指定一个唯一的 ID,如下所示:

    <table>
      <tr id="idrow1"><td> ADD AS MANY COLUMNS AS YOU LIKE  </td><td><button onclick="submitRowAsForm('idrow1')">SUBMIT ROW1</button></td></tr>
      <tr id="idrow2"><td> PUT INPUT FIELDS IN THE COLUMNS  </td><td><button onclick="submitRowAsForm('idrow2')">SUBMIT ROW2</button></td></tr>
      <tr id="idrow3"><td>ADD MORE THAN ONE INPUT PER COLUMN</td><td><button onclick="submitRowAsForm('idrow3')">SUBMIT ROW3</button></td></tr>
    </table>
    

    然后,在您的页面的 JavaScript 中包含以下函数。

    <script>
    function submitRowAsForm(idRow) {
      form = document.createElement("form"); // CREATE A NEW FORM TO DUMP ELEMENTS INTO FOR SUBMISSION
      form.method = "post"; // CHOOSE FORM SUBMISSION METHOD, "GET" OR "POST"
      form.action = ""; // TELL THE FORM WHAT PAGE TO SUBMIT TO
      $("#"+idRow+" td").children().each(function() { // GRAB ALL CHILD ELEMENTS OF <TD>'S IN THE ROW IDENTIFIED BY idRow, CLONE THEM, AND DUMP THEM IN OUR FORM
            if(this.type.substring(0,6) == "select") { // JQUERY DOESN'T CLONE <SELECT> ELEMENTS PROPERLY, SO HANDLE THAT
                input = document.createElement("input"); // CREATE AN ELEMENT TO COPY VALUES TO
                input.type = "hidden";
                input.name = this.name; // GIVE ELEMENT SAME NAME AS THE <SELECT>
                input.value = this.value; // ASSIGN THE VALUE FROM THE <SELECT>
                form.appendChild(input);
            } else { // IF IT'S NOT A SELECT ELEMENT, JUST CLONE IT.
                $(this).clone().appendTo(form);
            }
    
        });
      form.submit(); // NOW SUBMIT THE FORM THAT WE'VE JUST CREATED AND POPULATED
    }
    </script>
    

    那么我们在这里做了什么?我们为每一行赋予了一个唯一的 id,并在该行中包含了一个可以触发提交该行的唯一标识符的元素。当提交元素被激活时,一个新的表单被动态创建和设置。然后使用 jQuery,我们克隆包含在我们传递的行的&lt;td&gt; 中的所有元素,并将克隆附加到我们动态创建的表单中。最后,我们提交上述表格。

    【讨论】:

    • 我尝试了这种方法,但我使用的是 ajax 请求,所以现在所有这些行都附加在我的表格底部。试图找出隐藏这些的方法。
    • 好建议!为了让这段代码在 FireFox 中工作,我必须在 form.submit(); 之前添加form.style.display = "none"; document.body.appendChild(form);。并确保使用相同的 var idRow 而不是 id。
    • 很棒的答案。救了我几天。
    【解决方案5】:

    您可以使用form 属性id 将表单跨越多个元素,每个元素使用form 属性和表单名称,如下所示:

    <table>
         <tr>
              <td>
                   <form method="POST" id="form-1" action="/submit/form-1"></form>
                   <input name="a" form="form-1">
              </td>
              <td><input name="b" form="form-1"></td>
              <td><input name="c" form="form-1"></td>
              <td><input type="submit" form="form-1"></td>
         </tr>
    </table>
    

    【讨论】:

    • 出现错误 - “无法绑定到 'form',因为它不是 'input' 的已知属性。”
    • @BhupendraKumar 您使用什么系统会引发此错误?听起来您的开发环境对更深奥的属性一无所知。
    【解决方案6】:

    如果所有这些行都是相关的并且您需要更改表格数据...为什么不将整个表格包装在一个表单中,并将 GET 更改为 POST(除非您知道您不会发送超过 GET 请求可以发送的最大数据量)。

    我无法将整个表格包装在一个表单中,因为每行的某些输入字段是 input type="file" 并且文件可能很大。当用户提交表单时,我只想发布当前行的字段,而不是所有可能不需要大文件的行的所有字段,导致表单提交非常慢。

    所以,我尝试了不正确的嵌套:tr/form 和 form/tr。但是,它仅在不尝试将新输入动态添加到表单中时才有效。动态添加的输入不会属于错误嵌套的表单,因此不会被提交。 (有效的表单/表格动态输入提交就好了)。

    嵌套 div[display:table]/form/div[display:table-row]/div[display:table-cell] 导致网格列的宽度不均匀。当我将 div[display:table-row] 替换为 form[display:table-row] 时,我设法获得了统一的布局:

    div.grid {
        display: table;
    }
    
    div.grid > form {
        display: table-row;
    
    
    div.grid > form > div {
        display: table-cell;
    }
    div.grid > form > div.head {
        text-align: center;
        font-weight: 800;
    }
    

    为了在 IE8 中正确显示布局:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    ...
    <meta http-equiv="X-UA-Compatible" content="IE=8, IE=9, IE=10" />
    

    输出样本:

    <div class="grid" id="htmlrow_grid_item">
    <form>
        <div class="head">Title</div>
        <div class="head">Price</div>
        <div class="head">Description</div>
        <div class="head">Images</div>
        <div class="head">Stock left</div>
        <div class="head">Action</div>
    </form>
    <form action="/index.php" enctype="multipart/form-data" method="post">
        <div title="Title"><input required="required" class="input_varchar" name="add_title" type="text" value="" /></div>
    

    但是,让这段代码在 IE6/7 中运行会困难得多。

    【讨论】:

      【解决方案7】:

      如果您在每个td 中的trinputs 中都需要form,则可以在td 标签中添加form,并添加包含form 标签id 的属性'form'到外面inputs。 像这样的:

      <tr>
        <td>
          <form id='f1'>
            <input type="text">
          </form>
        </td>
        <td>
          <input form='f1' type="text">
        </td>
      </tr>
      

      【讨论】:

        【解决方案8】:

        如果您可以使用 javascript 并在您的网络上严格要求它,您可以将文本框、复选框和任何内容放在表格的每一行以及每一行的末尾放置按钮(或 rowSubmit 类的链接)“保存”。没有任何 FORM 标签。 JS 和 Ajax 模拟的形式如下:

        <script type="text/javascript">
        $(document).ready(function(){
          $(".rowSubmit").click(function()
          {
             var form = '<form><table><tr>' + $(this).closest('tr').html() + '</tr></table></form>';
             var serialized = $(form).serialize(); 
             $.get('url2action', serialized, function(data){
               // ... can be empty
             }); 
           });
        });        
        </script>
        

        你怎么看?

        PS:如果你用 jQuery 写这个:

        $("valid HTML string")
        $(variableWithValidHtmlString)
        

        它将变成 jQuery 对象,您可以像在 jQuery 中一样使用它。

        【讨论】:

        • PS:如果行是由 javascript 动态添加的,如果定义如图所示,事件“click”将不起作用。在这种情况下,通过 jQuery.live() 或 jQuery.on() 定义事件
        【解决方案9】:

        我赞同 Harmen 的 div 建议。或者,您可以将表格包装在表单中,并在提交前使用 javascript 捕获行焦点并通过 javascript 调整表单操作。

        【讨论】:

          【解决方案10】:

          我遇到了与原始问题中提出的问题类似的问题。我对样式为表格元素的 div 很感兴趣(不知道你能做到这一点!)并试了一下。但是,我的解决方案是让我的表格包含在标签中,但重命名每个输入和选择选项以成为数组的键,我现在正在对其进行解析以获取所选行中的每个元素。

          这是表格中的一行。请注意,键 [4] 是从数据库中检索到此表行的行的渲染 ID:

          <table>
            <tr>
              <td>DisabilityCategory</td>
              <td><input type="text" name="FormElem[4][ElemLabel]" value="Disabilities"></td>
              <td><select name="FormElem[4][Category]">
                  <option value="1">General</option>
                  <option value="3">Disability</option>
                  <option value="4">Injury</option>
                  <option value="2"selected>School</option>
                  <option value="5">Veteran</option>
                  <option value="10">Medical</option>
                  <option value="9">Supports</option>
                  <option value="7">Residential</option>
                  <option value="8">Guardian</option>
                  <option value="6">Criminal</option>
                  <option value="11">Contacts</option>
                </select></td>
              <td>4</td>
              <td style="text-align:center;"><input type="text" name="FormElem[4][ElemSeq]" value="0" style="width:2.5em; text-align:center;"></td>
              <td>'ccpPartic'</td>
              <td><input type="text" name="FormElem[4][ElemType]" value="checkbox"></td>
              <td><input type="checkbox" name="FormElem[4][ElemRequired]"></td>
              <td><input type="text" name="FormElem[4][ElemLabelPrefix]" value=""></td>
              <td><input type="text" name="FormElem[4][ElemLabelPostfix]" value=""></td>
              <td><input type="text" name="FormElem[4][ElemLabelPosition]" value="before"></td>
              <td><input type="submit" name="submit[4]" value="Commit Changes"></td>
            </tr>
          </table>
          

          然后,在 PHP 中,我使用以下方法将与提交按钮对应的行中的每个元素存储在一个数组 ($SelectedElem) 中。我使用print_r() 只是为了说明:

          $SelectedElem = implode(",", array_keys($_POST['submit']));
          print_r ($_POST['FormElem'][$SelectedElem]);
          

          也许这听起来很复杂,但事实证明它非常简单,并且保留了表的组织结构。

          【讨论】:

          • 这种方法的缺点是自动完成会为每一行保留单独的列表,这可能不是一个大问题,只是让最终用户感到困惑。此外,作为一批行提交可能会破坏服务器的 post_max_limit,这在 PHP 中意味着它会将数据丢弃。如果您的界面允许用户向表中添加行,这可能是一个严重的问题。
          【解决方案11】:

          表格不是用来做这个的,你为什么不使用&lt;div&gt;'s 和 CSS?

          【讨论】:

          • 表格不代表表格数据?我正在尝试做一个可编辑的网格。
          • 我不确定表单是否算作数据。它肯定不会验证您的方式,因为对于哪些标签必须/可以跟随 或 标签 有特定的限制
          • @vtortola 关键字是“数据”。在您的示例中,您使用它来控制输入表单布局,而不是向最终用户呈现数据。也许如果您解释了表格的用途,推荐一些替代方案会更容易。
          • 我见过的大多数可编辑网格的实现都使用包裹在表格周围的表单,然后每一行可能都有一个保存按钮,该按钮会将密钥传递给提交操作(或使用 ajax 和表单无论如何,提交并不意味着什么)。
          • 您正在收集数据,正如我在迟交的回答中所写的那样。你要的是display: table-cell;,可惜老的IE还在那儿……
          【解决方案12】:

          正如 Harmen 所说,就像不使用表格进行标记一样简单。毕竟,您不是在显示数据,而是在收集数据。

          我以问题 23 为例:http://accessible.netscouts-ggmbh.eu/en/developer.html#fb1_22_5

          在纸面上,它本来就很好。如果您必须显示结果,那可能没问题。
          但是您可以将其替换为... 4 个带有标签和选择的段落(选项将是第一行的标题)。每行一个段落,这要简单得多。

          【讨论】:

          • 我相信网格通常既显示数据又允许编辑。
          • 表格是 HTML 中的复杂内容。也是一种形式。当有更简单的解决方案时,我不会尝试两者都玩,这是两全其美的秘诀。而且我不是在谈论网格(视觉事物),有(或应该有)display: table-cell; 用于它,但元素表及其在 HTML 中的约束。
          猜你喜欢
          • 2013-08-29
          • 1970-01-01
          • 2016-12-26
          • 1970-01-01
          • 2017-01-12
          • 1970-01-01
          • 2017-04-20
          • 1970-01-01
          相关资源
          最近更新 更多