在选项卡式表单中间添加额外(嵌套)表单的最佳方法

Sch*_*els 12 php forms jquery jquery-ui-tabs

我有一个Web应用程序,主要由一个包含信息的大表单组成.表单分为多个选项卡,以使其对用户更具可读性:

<form>
<div id="tabs">
  <ul>
    <li><a href="#tab1">Tab1</a></li>
    <li><a href="#tab2">Tab2</a></li>
  </ul>
  <div id="tab1">A big table with a lot of input rows</div>
  <div id="tab2">A big table with a lot of input rows</div>
</div>
</form>
Run Code Online (Sandbox Code Playgroud)

表单是动态扩展的(额外的行添加到表中).每隔10秒,表单就会被序列化并与服务器同步.

我现在想在其中一个选项卡上添加交互式表单:当用户在字段中输入名称时,此信息将发送到服务器并返回与该名称关联的ID.此id用作某些动态添加的表单字段的标识符.

这样一个页面的快速草图将如下所示:

<form action="bigform.php">
<div id="tabs">
  <ul>
    <li><a href="#tab1">Tab1</a></li>
    <li><a href="#tab2">Tab2</a></li>
  </ul>
  <div id="tab1">A big table with a lot of input rows</div>
  <div id="tab2">
    <div class="associatedinfo">
    <p>Information for Joe</p>
    <ul>
      <li><input name="associated[26][]" /></li>
      <li><input name="associated[26][]" /></li>
    </ul>
    </div>

    <div class="associatedinfo">
    <p>Information for Jill</p>
    <ul>
      <li><input name="associated[12][]" /></li>
      <li><input name="associated[12][]" /></li>
    </ul>
    </div>
    <div id="newperson">
      <form action="newform.php">
        <p>Add another person:</p> 
        <input name="extra" /><input type="submit" value="Add" />
      </form>
    </div>
  </div>
</div>
</form>
Run Code Online (Sandbox Code Playgroud)

以上操作无效:HTML中不允许使用嵌套表单.但是,我真的需要在该选项卡上显示该表单:它是该页面功能的一部分.我还想要一个单独表单的行为:当用户在表单字段中返回时,按下"添加"提交按钮并在部分表单上触发提交操作.

解决这个问题的最佳方法是什么?

Dan*_*ien 10

您可以做的一件事是将"Add"输入元素的类型设置为"submit",将其设置为"button"并添加id用于注册click处理程序的属性:

<!-- ... -->
    <div id="newperson">
      <p>Add another person:</p> 
      <input id="extra_input" name="extra" /><input id="add_button" type="button" value="Add" />
    </div>
<!-- ... -->
Run Code Online (Sandbox Code Playgroud)

输入类型"按钮"的原因是页面上的结果按钮看起来与提交按钮完全相同,但在单击时默认不执行任何操作,允许您自定义其效果.此外,支持HTML 3.2或更高版本(包括HTML 5)的所有浏览器都支持输入类型"按钮" .

在Javascript的某个地方,您可能有一个函数,只要用户单击"添加"按钮,您就可以调用该函数.假设它被调用addAnotherPerson,您只需addAnotherPerson在单击处理程序中调用:

// This is jQuery code, but all JS frameworks that I have seen have a similar feature to register a click handler on a DOM element referenced by ID.
$("#add_button").click(function (event) {
    addAnotherPerson();
    $("#extra_input").val(""); // reset the value
});
Run Code Online (Sandbox Code Playgroud)

您还需要在"额外"文本输入中添加keydown处理程序,以便在用户按下Enter键时执行相同的操作:

$("#extra_input").keydown(function (event) {
    if (event.keyCode == 0xa || event.keyCode == 0xd) {
        addAnotherPerson();
        $("#extra_input").val(""); // reset the value
    }
});
Run Code Online (Sandbox Code Playgroud)

请务必将该属性添加autocomplete="off"到"额外"文本输入中.

addAnotherPerson函数可以发送包含"额外"文本框中的值的异步POST请求,如果合适,则在之后更新DOM.

编辑:如果您还想支持禁用Javascript的用户,那么通过name为每个提交按钮添加属性,每个提交按钮具有唯一的name属性值,您的服务器端应用程序将能够告诉用户单击了哪个按钮.

例如,从http://www.alanflavell.org.uk/www/trysub.html获取此代码:

<table>
<tr><td align=left><label for="aquavit_button"><input id="aquavit_button" type="submit" name="aquavit" value="[O]"> Aquavit</label></td></tr>
<tr><td align=left><label for="beer_button"><input id="beer_button" type="submit" name="beer" value="[O]"> Beer</label></td></tr>
<tr><td align=left><label for="champagne_button"><input id="champagne_button" type="submit" name="champagne" value="[O]"> Champagne</label></td></tr>
<tr><td align=left><label for="water_button"><input id="water_button" type="submit" name="water" value="[O]"> Dihydrogen monoxide</label></td></tr>
</table>
Run Code Online (Sandbox Code Playgroud)

如果用户点击"Beer"旁边的"[O]"按钮,则浏览器会发送"啤酒"POST变量,但不会发送"aquavit","香槟"或"水"POST变量.请在http://www.alanflavell.org.uk/www/trysub.html上试试.

这种技术的一个棘手问题是用户通过在文本输入中按Enter键来提交表单.Firefox为表单中的第一个提交按钮发送POST变量(在本例中为"aquavit"),而Internet Explorer不为任何提交按钮发送POST变量.您可以通过在表单的最开头添加隐藏的无名提交按钮来修补此差异:

<form action="bigform.php"><input type="submit" style="display:none;" />
<!-- ... -->
Run Code Online (Sandbox Code Playgroud)

编辑2:如果您始终确保在提交大表单之前通过Javascript清除"额外"文本输入中的值,那么您将能够判断用户是否已禁用 Javascript,并且他们按下"确认"中的Enter键.通过检查服务器端的"额外"POST变量是否为空,额外的"文本输入(表示他们希望运行添加人员操作)".如果它不为空,那么您可以假设用户已禁用Javascript并且他们想要添加人员.

添加此代码:

$("#bigform").submit(function (event) {
    $("#extra_input").val(""); // reset the value in the "extra" text input
    return true;
});
Run Code Online (Sandbox Code Playgroud)


Dav*_*ang 6

HTML应该是语义的,应该首先考虑它 - 也就是说它应该有一个清晰的结构和意义,而不需要理解javascript的顶部.就像a <ul>应该只包含<li>元素的方式一样,a <form>应该只有一个目的.使用javascript通过检索动态数据来增强表单很好,但是如果使用额外的HTTP POST(修改服务器上的数据的类型),那么这实际上代表了第二个目的,因此应该使用第二个表单.第二种形式具有自己的"动作"属性,表示此处发生了明显的行为,并且不仅在概念上更合理,而且在必要时更容易分析,调试或扩展.

<form id="bigform" action="bigform.php">
    <!-- Tabs here -->
</form>
<form id="newperson" action="newform.php">
   <input name="extra">
   <button type="submit" value="Add">
   <!-- Note also the use of <button> instead of <input> -->
</form>
Run Code Online (Sandbox Code Playgroud)

重要的是,您仍然可以在主窗体内实现所需的流程.在主窗体上,使用a而不是使用嵌套窗体<fieldset>.此字段集将充当newperson表单的代理.这里的输入可以有一个ID,但不应该有一个名称,因为它的值不应该与主表单一起提交.正如在其他答案中已经提到的,按钮应该更改为"按钮"类型而不是"提交".

<form id="bigform" action="bigform.php">
    <!-- Tabs here -->
    <fieldset id="newpersonProxy">
        <input id="extra">
        <button type="button" value="Add">
    </fieldset>
</form>
Run Code Online (Sandbox Code Playgroud)

现在通过Javascript不显眼地添加所需的行为:

  1. 隐藏第二种形式,#newperson.
  2. 通过绑定到任何输入的keyup事件#newpersonProxy以及按钮的click事件来响应"提交" .对于keyup事件,使用event.which而不是event.keyCodejQuery标准化它.你想要event.which == 13输入密钥.
  3. 然后在调用之前将值从代理输入复制到真实表单$("#newperson").submit().

这有效地将序列化和发送数据的责任委托给第二种形式,允许将任何类型的逻辑附加到第二种形式,并从第一种形式解除耦合.

此外,由于首先考虑功能HTML,一个简单的调整可以允许表单在没有Javascript的情况下完美地工作 - 只需隐藏<fieldset>使用CSS,并使用Javascript显示它.如果Javascript被关闭,标签将分开,嵌套的字段集将被隐藏,第二个表格将被显示(并且完全正常运行,而不是通过AJAX).