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

时间:2010-12-27 23:43:09

标签: php jquery forms jquery-ui-tabs

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

<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>

表单是动态扩展的(将额外的行添加到表中)。 每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>

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

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

9 个答案:

答案 0 :(得分:10)

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

<!-- ... -->
    <div id="newperson">
      <p>Add another person:</p> 
      <input id="extra_input" name="extra" /><input id="add_button" type="button" value="Add" />
    </div>
<!-- ... -->

输入类型“按钮”的原因是页面上的结果按钮看起来与提交按钮完全相同,但在单击时默认不执行任何操作,允许您自定义其效果。此外,支持HTML 3.2或更高版本including 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
});

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

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

请务必将属性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>

如果用户点击“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;" />
<!-- ... -->

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

添加此代码:

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

答案 1 :(得分:6)

HTML应该是语义的,应该首先考虑 - 即它应该具有清晰的结构和意义,而不了解javascript位于顶部的内容。与<ul>应该只包含<li>元素的方式一样,<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>

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

<form id="bigform" action="bigform.php">
    <!-- Tabs here -->
    <fieldset id="newpersonProxy">
        <input id="extra">
        <button type="button" value="Add">
    </fieldset>
</form>

现在通过Javascript 不加干扰地添加所需的行为:

  1. 隐藏第二个表单#newperson
  2. 通过绑定#newpersonProxy内任何输入的keyup事件以及按钮的click事件来响应“提交”。对于keyup事件,使用event.which而不是event.keyCode,因为jQuery会对此进行规范化。您希望输入密钥为event.which == 13
  3. 然后在调用$("#newperson").submit()之前将值从代理输入复制到真实表单。
  4. 这有效地将序列化和发送数据的责任委托给第二种形式,允许将任何类型的逻辑附加到第二种形式,并从第一种形式解除耦合。

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

答案 2 :(得分:2)

以下内容应该这样做。

如果禁用JavaScript,则需要检测用户是否按下了“添加”submitButton

$_POST["submitButton"] == "Add"


    <!-- other stuff goes here -->

    <div id="newperson">
        <p>Add another person:</p> 
        <input name="extra" id="extra" /><input name="submitButton" id="addPerson" type="submit" value="Add" />
    </div>
  </div>
</div>
</form>
<script>
    var extra = $("#extra"),
        addPerson = $("#addPerson").click(function(e){
        // val would be the new person's name, e.g., "David"
        var val = extra.val();
        // you will want to give the user some AJAXy feedback here.

        $.post(this.form.action, {"extra": val}, function(response){
            // rest the extra div.
            extra.val("");

            /* 'response' could look like:                             */
            // <div class="associatedinfo">
            //      <p>Information for David</p>
            //      <ul>
            //        <li><input name="associated[13][]" /></li>
            //        <li><input name="associated[13][]" /></li>
            //      </ul>
            //   </div>
            $(response).insertBefore("#newperson");

            // or 'response' could be json data, or whatever. I have a feeling
            // you know enough about jQuery to handle the response-data.  :-)

        });
        // prevent it from bubbling up.
        e.preventDefault();
    });

    extra.keydown(function(e){
        // submit the new person's name via ajax if enter is pressed.
        if(e.keyCode === 13){
            addPerson.click();
            e.preventDefault();
        }
    });
</script>

答案 3 :(得分:2)

这并不像其他答案那么冗长,但是......

应该非常容易;)

  • 完全摆脱您的FORM标签
  • 使用jQuery获取输入字段值
  • 当用户点击提交“a”元素看起来像提交按钮时,它只会发出一个ajax请求,捕获输入字段的值。

这是一个example,它显示了我正在引用的格式 ,但是它保留了表单标记,是我使用scriptaculous库时的一个较旧的示例。这是the JS,它演示了一些结构。

如果你给我+1,让我知道你喜欢这个答案,我会为你开发一个功能性的例子;)

干杯! 柯克

答案 4 :(得分:1)

为什么不嵌套表单对象并在一个php代码中处理所有操作...

# have this form appended to the DOM via ajax/js when a link is clicked
<div id="newperson">
  <p>Add another person:</p> 
  <input type="text" name="associated[new][]" />
</div>

然后在后端使用php逻辑创建关联,如果它是“new”:

foreach($_POST['associated'] as $obj) {
  if($obj == "new")
    // create a new record
  else
    // do your other processing
}

答案 5 :(得分:1)

你可以在父表单之外移动添加表单并使用CSS隐藏它,然后,正如另一张海报所说,用一个具有正确id的按钮替换添加表单的提交按钮,最后,挂钩到两个onkeypress在输入上,单击按钮以模拟实际添加表单的提交。

<form action="bigform.php">

    ....

    <div id="newperson">
      <p>Add another person:</p> 
      <input name="extra" /><button value="Add"/>
    </div>
  </div>
</div>
</form>
<div style='display:none;'>
    <form action="newform.php" id='add_person_form'>
      <input id='add_person_name' />
      <input type="submit" id='add_person_submit' />
    </form>
</div>

<script>
$('#newperson input').keyup(function(e) {
    if(e.keyCode == 13) submitNewPersonForm();
});
$('#newperson button').click(function(e) {
    submitNewPersonForm();
});

function submitNewPersonForm() {
    // copy the content from the placeholder form
    $('#add_person_name').val($("#newperson input").val());
    // submit this form
    $("#add_person_form").submit();
}
</script>

据我所知,这应该保留原始功能所需的一切。

注意:#add_person_form表单上并不真正需要提交按钮,我只是将其保留在那里,以便您可以轻松查看我将表单移动到的位置。

答案 6 :(得分:1)

我看到处理类似场景的方式是为“内部”表单创建一个模态页面,因此不需要嵌套。我没有看到这种方法严重阻碍了页面的流动。

否则通过AJAX提交“内部”表单或整个表单的其他建议也可以。

答案 7 :(得分:1)

您不需要嵌套表单,可以使用其他表单(非嵌套)并使用绝对定位将其放置在页面的任何位置。所有这些创建的动态控件的id与用户输入的名称相关似乎非常复杂......如果你能分享你可能想要解决的业务问题,我们可以有一个更简单的解决方案。

答案 8 :(得分:0)

您可以使用ajax或使其他形式在第一个之外,并使用绝对DIV图层定位。

使用javascript轻松读取图层位置。首先,您将创建一个具有预定义高度的占位符,然后您可以在占位符上方显示该表单。

<form>

...
  <div style='height: 300px;' class='placeholder'> ... </div>
</form>

<form>...<form>

显示.placeholder

的第二个表单