我知道xhtml不支持嵌套的表单标签,我已经阅读了其他答案 这里有关于这个主题的stackoverflow,但我仍然没有想出一个优雅的问题解决方案。
有人说你不需要它,他们想不到这种情况是否需要。好吧,我个人无法想到一个我不需要它的场景。
让我们看一个非常简单的例子:
您正在一个博客的应用程序,你必须与创建一个新的职位和一个工具栏与“行动”像“保存”,“删除”,“取消”某些字段的形式。
<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表单和提交按钮。
由于操作网址在表单标签定义,而不是在每个单独提交按钮,我们唯一的选择是张贴到一个通用网址,然后开始“如果......那么......否则”确定的名称提交的按钮。不是很优雅,但我们唯一的选择,因为我们不想依赖javascript。
唯一的问题是按“删除”,即使此操作所需的唯一内容是带有post-id的隐藏输入,也会提交服务器上的所有表单字段。不是非常大的交易在这个小例子,但我有一个领域的数百个(这么说)和选项卡在我的LOB应用形式的(因为要求)必须在提交的所有信息一去,在任何情况下,这似乎是非常低效而浪费。如果支持表单嵌套,我至少可以在其自己的表单中包含“删除”提交按钮,只包含post-id字段。
您可以说“只需将”删除“视为链接而不是提交”。这在很多层面都是错误的,但最重要的是因为像这里的“删除”这样的副作用动作绝不应该是GET请求。
所以我的问题(特别是那些说他们不需要形式嵌套的人)是你做什么的?是否有任何优雅的解决方案,我缺少或底线真的“需要javascript或提交一切”?
答案 0 :(得分:175)
我知道这是一个老问题,但HTML5提供了几个新选项。
第一种方法是将表单与标记中的工具栏分开,为删除操作添加另一个表单,并使用form
属性将工具栏中的按钮与各自的表单相关联。
<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>
此选项非常灵活,但原始帖子还提到可能需要使用单个表单执行不同的操作。 HTML5再次受到拯救。您可以在提交按钮上使用formaction
属性,因此同一表单中的不同按钮可以提交到不同的网址。这个例子只是将一个克隆方法添加到表单外部的工具栏中,但它在表单中嵌套的方式相同。
<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
这些新功能的优势在于它们无需JavaScript即可以声明方式完成所有这些操作。缺点是旧浏览器不支持它们,因此您必须为旧浏览器进行一些填充。
答案 1 :(得分:53)
我将按照您的描述完全实现:将所有内容提交到服务器并执行简单的if / else检查单击了哪个按钮。
然后我会实现一个Javascript调用,它会绑定到表单的onsubmit事件,该事件将在表单提交之前检查,并且只将相关数据提交给服务器(可能通过页面上的第二个表单以及需要处理的ID)将事物作为隐藏输入,或者使用您需要作为GET请求传递的数据刷新页面位置,或者向服务器发送Ajax帖子,或者......)。
这样没有Javascript的人就可以正常使用表单,但是服务器负载是偏移的,因为拥有Javascript的人只提交所需的单个数据。让自己专注于只支持一方或另一方真的会不必要地限制你的选择。
或者,如果您在公司防火墙后面工作,并且每个人都禁用了Javascript,您可能需要执行两个表单并使用一些CSS魔术使其看起来像删除按钮是第一个表单的一部分。 / p>
答案 2 :(得分:16)
您可以在页面上并排显示表单,但不能嵌套。然后使用CSS使所有按钮排成一行?
<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>
答案 3 :(得分:13)
HTML5具有“表单所有者”的概念 - 输入元素的“表单”属性。它允许模拟嵌套表单并解决问题。
答案 4 :(得分:11)
有点老话题,但这个可能对某人有用:
如上所述 - 您可以使用虚拟表格。 我不得不在不久前克服这个问题。起初我完全忘记了这个HTML限制,只是添加了嵌套表单。结果很有趣 - 我从嵌套中丢失了我的第一个表单。然后,在实际的嵌套表单之前简单地添加一个虚拟表单(将从浏览器中删除),这是一种“技巧”。
就我而言,它看起来像这样:
<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不检测主窗体中的参数。无论输入如何,$ _REQUEST全局都是空的。内心形式似乎无处不在。
尚未测试此处描述的其他建议 - 围绕嵌套表单的字段集。
编辑:框架集不起作用! 我只是在其他人之后添加了Main表单(没有更多的嵌套表单),并使用jQuery的“clone”在按钮单击时复制表单中的输入。为每个克隆的输入添加.hide()以保持布局不变,现在它就像魅力一样。
答案 5 :(得分:4)
我认为杰森是对的。如果您的“删除”操作是最小的操作,请将其单独放在一个表单中,并将其与其他按钮对齐,以使界面看起来像一个统一的表单,即使它不是。
或者,当然,重新设计你的界面,让人们完全删除其他地方,而不需要他们看到巨大的形式。
答案 6 :(得分:2)
如果没有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>
使用处理脚本中隐藏的“任务”字段进行适当分支。
答案 7 :(得分:1)
使用iframe
作为嵌套表单。如果他们需要共享字段,那么......它并不是真正嵌套的。
答案 8 :(得分:1)
我的解决方案是让按钮调用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>
答案 9 :(得分:1)
我仍然对此讨论感兴趣。原帖后面是&#34;要求&#34; OP似乎分享 - 即具有向后兼容性的形式。作为撰写本文时工作的人有时必须支持IE6(以及未来几年),我会深入研究。
如果没有推动框架(所有组织都希望在兼容性/健壮性方面保证自己,并且我没有将此讨论作为框架的理由),Drupal对此问题的解决方案很有意思。 Drupal也是直接相关的,因为该框架有一个很长时间的政策,它应该在没有Javascript的情况下工作(只有你想要的话)&#34;即OP的问题。
Drupal使用它相当广泛的 form.inc 函数来查找triggering_element(是的,这是代码中的名称)。请参阅form_builder的API页面上列出的代码的底部(如果您想深入了解详情,建议使用来源 - drupal-x.xx / includes / form.inc )。构建器使用自动HTML属性生成,通过它,可以在返回时检测按下了哪个按钮,并相应地进行操作(这些也可以设置为运行单独的进程)。
除了表单构建器之外,Drupal还会分割数据并删除&#39;可能出于原始帖子中提到的原因,将操作转换为单独的网址/表单。这需要某种搜索/列表步骤(呻吟另一种形式!,但用户友好)作为初步。但这有利于消除&#34;提交所有内容&#34;问题。数据的大表格用于其预期目的,数据创建/更新(甚至是合并&#39;操作)。
换句话说,解决问题的一种方法是将表单转换为两个,然后问题就消失了(HTML方法也可以通过POST来纠正)。
答案 10 :(得分:0)
好吧,如果您提交表单,浏览器也会发送输入提交名称和值。 所以你可以做的是
<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>
所以在服务器端你只需要查找启动宽度字符串“action:”的参数,其余部分告诉你采取什么行动
所以当您点击按钮时,保存浏览器会向您发送类似foo = asd&amp; action:save = Save
的内容答案 11 :(得分:-1)
如果你真的不想使用多个表单(如Jason sugests),那么使用按钮和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,这将使一半的页面无效。
答案 12 :(得分:-1)
在回答Yar在他自己的回答评论中发布的问题时,我提出了一些可以调整iframe大小的JavaScript。对于表单按钮的情况,可以安全地假设iframe将位于同一个域中。这是我使用的代码。您将不得不改变自己网站的数学/常量:
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>
答案 13 :(得分:-1)
我想出了一个用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>
答案 14 :(得分:-1)
我通过包含一个复选框来解决这个问题,具体取决于该人想要做什么形式。 然后用1个按钮提交整个表格。
答案 15 :(得分:-2)
或者您可以动态分配表单操作...可能不是最佳解决方案,但确实可以减轻服务器端逻辑......
<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>