你如何克服html表格嵌套限制?

我知道xhtml不支持嵌套窗体标签,我已经阅读了其他答案
这里在关于这个问题的计算器,但我还没有想出一个优雅的解决scheme的问题。

有人说,你不需要它,他们不能想到这是需要的情况。 那么,我个人不能想到一个我不需要它的场景。

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

你正在创build一个博客应用程序,你有一个表单,有一些字段用于创build一个新的post和一个带有“保存”,“删除”,“取消”等“操作”的工具栏。

<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表单和提交button。

由于动作URL是在Form标签中定义的,而不是在每个单独的提交button中,我们唯一的select是发布到一个通用的url,然后启动“if … then … else”来确定button的名称已提交。 不是很优雅,但是我们唯一的select,因为我们不想依靠javascript。

唯一的问题是,按下“删除”,将提交服务器上的所有表单字段,即使这个动作只需要一个隐藏的input与后ID。 这个小例子并不是什么大不了的事情,但是我在我的LOB应用程序中有数百个(可以这么说)字段和标签的表单(因为需求)必须一次性提交所有内容,而且在任何情况下,这似乎都是非常低效的和浪费。 如果表单嵌套被支持,我至less可以用自己的forms包装“删除”提交button,只有post-id字段。

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

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

我将按照您所描述的完全实现:将所有内容提交给服务器,并执行一个简单的if / else来检查单击了哪个button。

然后,我会实现一个Javascript调用绑定到窗体的onsubmit事件,将在提交表单之前检查,并只提交相关的数据到服务器(可能通过页面上的第二个表单与需要处理的东西作为一个隐藏的input,或刷新页面的位置与您需要作为GET请求传递的数据,或者做一个Ajax张贴到服务器,或…)。

这样,没有Javascript的人就可以使用这个表单了,但是服务器的负载被抵消了,因为有Javascript的人只提交了所需要的单个数据。 让自己专注于只支持一个或另一个真的限制你的select不必要的。

另外,如果你在企业防火墙的后面工作,而且每个人都禁用了Javascript,那么你可能需要做两种forms,并使用一些CSS魔法,使其看起来像删除button是第一种forms的一部分。

我知道这是一个老问题,但HTML5提供了一些新的select。

首先是将标签中的表单与工具栏分开,为删除操作添加另一个表单,并使用form属性将工具栏中的button与各自的表单相关联。

 <form id="saveForm" action="/post/dispatch/save" method="post"> <input type="text" name="foo" /> <!-- several of those here --> </form> <form id="deleteForm" action="/post/dispatch/delete" method="post"> <input type="hidden" value="some_id" /> </form> <div id="toolbar"> <input type="submit" name="save" value="Save" form="saveForm" /> <input type="submit" name="delete" value="Delete" form="deleteForm" /> <a href="/home/index">Cancel</a> </div> 

这个选项是非常灵活的,但原来的post也提到可能有必要用一个表单执行不同的操作。 HTML5又来了。 您可以在提交button上使用formaction属性,因此同一表单中的不同button可以提交到不同的URL。 这个例子只是将一个克隆方法添加到表单外的工具栏中,但它将在表单中嵌套。

 <div id="toolbar"> <input type="submit" name="clone" value="Clone" form="saveForm" formaction="/post/dispatch/clone" /> </div> 

http://www.whatwg.org/specs/web-apps/current-work/#attributes-for-form-submission

这些新function的优点是,他们所有这些声明没有JavaScript。 缺点是旧版浏览器不支持它们,所以你必须为旧版浏览器做一些填充。

你可以在页面上并排显示表格,但不能嵌套。 然后使用CSS来使所有的button排列漂亮?

 <form method="post" action="delete_processing_page"> <input type="hidden" name="id" value="foo" /> <input type="submit" value="delete" class="css_makes_me_pretty" /> </form> <form method="post" action="add_edit_processing_page"> <input type="text" name="foo1" /> <input type="text" name="foo2" /> <input type="text" name="foo3" /> ... <input type="submit" value="post/edit" class="css_makes_me_pretty" /> </form> 

HTML5有一个“form owner”的概念 – input元素的“form”属性。 它允许模拟嵌套表单,并将解决问题。

旧的话题,但这个可能对某人有用:

正如上面提到的 – 你可以使用虚拟forms。 前段时间我不得不解决这个问题。 起初我完全忘记了这个HTML限制,只是添加了嵌套表单。 结果是有趣的 – 我失去了我的第一个forms从嵌套。 然后,事实certificate,在实际的嵌套表单之前添加一个虚拟表单(这将从浏览器中删除)是一种“技巧”。

在我的情况下,它看起来像这样:

 <form id="Main"> <form></form> <!--this is the dummy one--> <input...><form id="Nested 1> ... </form> <input...><form id="Nested 1> ... </form> <input...><form id="Nested 1> ... </form> <input...><form id="Nested 1> ... </form> ...... </form> 

适用于Chrome,FireFox和Safari。 IE最多9(不知道10),Opera没有检测到主要forms的参数。 无论input如何,$ _REQUEST全局都是空的。 内在的forms似乎在任何地方都很好。

还没有testing过这里描述的另一个build议 – 围绕嵌套窗体的fieldset。

编辑 :框架没有工作! 我简单地添加了主窗体(没有更多的嵌套窗体),并使用jQuery的“克隆”在button单击窗体上重复input。 将.hide()添加到每个克隆的input,以保持布局不变,现在它就像一个魅力。

我认为杰森是正确的。 如果您的“删除”操作是最小化的操作,则将其设置为单独的forms,并将其与其他buttonalignment,以使界面看起来像一个统一的forms,即使它不是。

或者,当然,重新devise你的界面,让别人完全删除其他地方,根本不需要他们去看这个巨人形态。

我会这样做,没有JavaScript的一种方法是添加一组单选button,定义要采取的行动:

  • 更新
  • 删除
  • 随你

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

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

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

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

为嵌套的表单使用iframe 。 如果他们需要分享领域,那么…它不是真的嵌套。

我的解决scheme是让button调用JS函数写入,然后提交forms与主窗体

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

那么,如果你提交表单,浏览器也会发送一个input提交的名字和值。 所以你可以做的是

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

所以在服务器端,你只是寻找参数,开始宽度string“行动:”和其余部分告诉你要采取什么行动

所以当你点击button保存浏览器发送给你像foo = asd&动作:保存=保存

这个讨论仍然是我感兴趣的。 原始文章背后是OP似乎分享的“要求” – 即具有向后兼容性的forms。 作为写作时的工作有时必须支持IE6(以及未来几年)的人,我将其挖掘出来。

在不推动框架的情况下(所有组织都希望保证兼容性/健壮性,而且我没有用这个讨论作为框架的理由),Drupal解决这个问题的方法很有意思。 Drupal也是直接相关的,因为框架有一个很长的时间政策,“它应该工作没有JavaScript(只要你想)”即OP的问题。

Drupal使用相当广泛的form.inc函数来查找triggering_element(是的,这就是代码中的名字)。 查看form_builder的API页面上列出的代码底部(如果您想深入细节,build议使用源代码 – drupal-x.xx / includes / form.inc )。 构build器使用自动生成的HTML属性,通过它可以返回检测哪个button被按下,并据此采取行动(这些也可以设置为运行单独的进程)。

除了表单构build器之外,Drupal会将数据“删除”操作拆分成单独的URL /表单,这可能是由于原始文章中提到的原因。 这需要某种search/列表步骤( 呻吟另一种forms!,但用户友好)作为初步。 但是这样做的好处是消除了“提交一切”的问题。 数据的大forms被用于预期目的,数据创build/更新(甚至是“合并”动作)。

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

如果你真的不想使用多种forms(如杰森sugests),然后使用button和onclick处理程序。

 <form id='form' name='form' action='path/to/add/edit/blog' method='post'> <textarea name='message' id='message'>Blog message here</textarea> <input type='submit' id='save' value='Save'> </form> <button id='delete'>Delete</button> <button id='cancel'>Cancel</button> 

然后在JavaScript(我在这里使用jQuery容易)(即使是添加一些onclick处理程序是相当矫枉过正)

 $('#delete').click( function() { document.location = 'path/to/delete/post/id'; }); $('#cancel').click( function() { document.location = '/home/index'; }); 

另外我知道,这将使一半的页面不工作没有JavaScript。

为了回应Yar在他自己的回答中发表的评论,我介绍了一些可以调整iframe大小的JavaScript。 对于表单button的情况,假设iframe将在同一个域上是安全的。 这是我使用的代码。 你将不得不改变你自己的网站的math/常量:

 function resizeIFrame(frame) { try { innerDoc = ('contentDocument' in frame) ? frame.contentDocument : frame.contentWindow.document; if('style' in frame) { frame.style.width = Math.min(755, Math.ceil(innerDoc.body.scrollWidth)) + 'px'; frame.style.height = Math.ceil(innerDoc.body.scrollHeight) + 'px'; } else { frame.width = Math.ceil(innerDoc.body.scrollWidth); frame.height = Math.ceil(innerDoc.body.scrollHeight); } } catch(err) { window.status = err.message; } } 

然后像这样调用它:

 <iframe ... frameborder="0" onload="if(window.parent && window.parent.resizeIFrame){window.parent.resizeIFrame(this);}"></iframe> 

我只是想出了一个用jquery做的好方法。

 <form name="mainform"> <div id="placeholder"> <div> </form> <form id="nested_form" style="position:absolute"> </form> <script> $(document).ready(function(){ pos = $('#placeholder').position(); $('#nested_form') .css('left', pos.left.toFixed(0)+'px') .css('top', pos.top.toFixed(0)+'px'); }); </script> 

我通过添加一个checkbox来解决这个问题,具体取决于这个人希望做什么的forms。 然后用1个button提交整个表单。

另外,你可以指定表单actiob飞…可能不是最好的解决scheme,但肯定会减轻服务器端的逻辑…

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