我知道XHTML不支持嵌套的表单标记,我已经在Stack Overflow上阅读了关于这个主题的其他答案,但我仍然没有找到一个优雅的解决方案。

有些人说你不需要它,他们想不出有什么场景会需要它。就我个人而言,我想不出任何一种情况下我不需要它。

让我们看一个非常简单的例子:

你正在制作一个博客应用程序,你有一个带有一些字段的表单用于创建新帖子,还有一个带有“操作”的工具栏,如“保存”、“删除”、“取消”。

<form
 action="/post/dispatch/too_bad_the_action_url_is_in_the_form_tag_even_though_conceptually_every_submit_button_inside_it_may_need_to_post_to_a_diffent_distinct_url"
method="post">

    <input type="text" name="foo" /> <!-- several of those here -->
    <div id="toolbar">
        <input type="submit" name="save" value="Save" />
        <input type="submit" name="delete" value="Delete" />
        <a href="/home/index">Cancel</a>
    </div>
</form>

我们的目标是以一种不需要JavaScript的方式编写表单,只需要普通的HTML表单和提交按钮。

由于动作URL是在Form标签中定义的,而不是在每个单独的提交按钮中,所以我们唯一的选择是发布到一个通用URL,然后开始“if…then…”Else”来确定提交的按钮的名称。不是很优雅,但这是我们唯一的选择,因为我们不想依赖JavaScript。

The only problem is that pressing "Delete", will submit ALL the form fields on the server even though the only thing needed for this action is a Hidden input with the post-id. Not very big deal in this small example, but I have forms with hundreds (so to speak) of fields and tabs in my LOB applications that (because of requirements) have to submit everything in one-go and in any case this seems very inefficient and a waste. If form nesting was supported, I would at least be able to wrap the "Delete" submit button inside it's own form with only the post-id field.

你可能会说“只是实现‘删除’链接,而不是提交”。这在很多层面上都是错误的,但最重要的是,像“Delete”这样的副作用操作永远不应该是GET请求。

所以我的问题是(特别是对那些说他们不需要表单嵌套的人)你会做什么?有什么优雅的解决方案,我错过或底线真的是“要么需要JavaScript或提交一切”?


当前回答

我认为杰森是对的。如果你的“删除”操作是一个最小的操作,那就把它单独放在一个表单中,并把它与其他按钮对齐,这样界面看起来就像一个统一的表单,即使它不是。

或者,当然,重新设计你的界面,让人们完全删除其他地方,这根本不需要他们看到巨大的形式。

其他回答

在没有javascript的情况下,我可以添加一组单选按钮来定义要采取的操作:

更新 删除 无论

然后,操作脚本将根据单选按钮集的值采取不同的操作。

另一种方法是按照您的建议在页面上放置两个表单,只是不嵌套。虽然布局可能很难控制:

<form name="editform" action="the_action_url"  method="post">
   <input type="hidden" name="task" value="update" />
   <input type="text" name="foo" />
   <input type="submit" name="save" value="Save" />
</form>

<form name="delform" action="the_action_url"  method="post">
   <input type="hidden" name="task" value="delete" />
   <input type="hidden" name="post_id" value="5" />
   <input type="submit" name="delete" value="Delete" />
</form>

在处理脚本中使用隐藏的“task”字段进行适当的分支。

我仍然对这个讨论感兴趣。在最初的帖子后面是OP似乎共享的“需求”——即具有向后兼容性的表单。在我写这篇文章的时候,我的工作有时必须支持IE6(并且在未来的几年里),我理解这一点。

在不推动框架的情况下(所有组织都希望在兼容性/健壮性方面让自己放心,我并不是用这个讨论作为框架的理由),Drupal解决这个问题的方案是有趣的。Drupal也是直接相关的,因为这个框架有一个很长时间的政策,即“它应该在没有Javascript的情况下工作(只有当你想要的时候)”,即OP的问题。

Drupal使用相当广泛的形式。Inc函数来查找triggering_element(是的,这是代码中的名称)。请参阅form_builder API页面上列出的代码的底部(如果您想深入了解细节,建议使用源代码drupal-x.xx/includes/form.inc)。构建器使用自动HTML属性生成,通过它,可以在返回时检测按下了哪个按钮,并相应地采取行动(这些也可以设置为运行单独的进程)。

除了表单构建器之外,Drupal还将数据“删除”操作分割到单独的url /表单中,可能是出于最初文章中提到的原因。这需要一些搜索/列表步骤(另一种形式!但是用户友好的)作为一个初步。但这样做的好处是消除了“提交所有内容”的问题。包含数据的大表单用于预期目的,即数据创建/更新(甚至是“合并”操作)。

换句话说,解决这个问题的一种方法是将表单转换为两个,然后问题就消失了(HTML方法也可以通过POST进行纠正)。

我的解决方案是让按钮调用JS函数编写,然后提交表单与主表单

<head>
<script>
function removeMe(A, B){
        document.write('<form name="removeForm" method="POST" action="Delete.php">');
        document.write('<input type="hidden" name="customerID" value="' + A + '">');
        document.write('<input type="hidden" name="productID" value="' + B + '">');
        document.write('</form>');
        document.removeForm.submit();
}
function insertMe(A, B){
        document.write('<form name="insertForm" method="POST" action="Insert.php">');
        document.write('<input type="hidden" name="customerID" value="' + A + '">');
        document.write('<input type="hidden" name="productID" value="' + B + '">');
        document.write('</form>');
        document.insertForm.submit();
}
</script>
</head>

<body>
<form method="POST" action="main_form_purpose_page.php">

<input type="button" name="remove" Value="Remove" onclick="removeMe('$customerID','$productID')">
<input type="button" name="insert" Value="Insert" onclick="insertMe('$customerID','$productID')">

<input type="submit" name="submit" value="Submit">
</form>
</body>

或者,你也可以在动态中分配表单actiob…可能不是最好的解决方案,但确实缓解了服务器端逻辑……

<form name="frm" method="post">  
    <input type="submit" value="One" onclick="javascript:this.form.action='1.htm'" />  
    <input type="submit" value="Two" onclick="javascript:this.form.action='2.htm'" />  
</form>

如果你提交一个表单,浏览器也会发送一个输入提交名称和值。 所以你能做的是

<form   
 action="/post/dispatch/too_bad_the_action_url_is_in_the_form_tag_even_though_conceptually_every_submit_button_inside_it_may_need_to_post_to_a_diffent_distinct_url"  
method="post">  

    <input type="text" name="foo" /> <!-- several of those here -->  
    <div id="toolbar">
        <input type="submit" name="action:save" value="Save" />
        <input type="submit" name="action:delete" value="Delete" />
        <input type="submit" name="action:cancel" value="Cancel" />
    </div>
</form>

所以在服务器端,你只需要寻找以width string "action:"开头的参数,剩下的部分告诉你采取什么行动

所以当你点击保存按钮时,浏览器会给你发送类似foo=asd&action: Save =Save的东西