您如何克服 HTML 表单嵌套限制?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/597596/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do you overcome the HTML form nesting limitation?
提问by gCoder
I know that XHTML doesn't support nested form tags and I have already read other answers here on Stack Overflow regarding this subject, but I still haven't figured out an elegant solution to the problem.
我知道 XHTML 不支持嵌套表单标签,并且我已经在 Stack Overflow 上阅读了有关此主题的其他答案,但我仍然没有找到解决该问题的优雅方法。
Some say you don't need it and that they can't think of a scenario were this would be needed. Well, personally I can't think of a scenario that I haven'tneeded it.
有人说你不需要它,而且他们想不出需要它的场景。嗯,我个人不认为一个场景,我的没有需要它。
Let's see a very simple example:
让我们看一个非常简单的例子:
You are making a blog app and you have a form with some fields for creating a new post and a toolbar with "actions" like "Save", "Delete", "Cancel".
您正在制作一个博客应用程序,并且您有一个表单,其中包含一些用于创建新帖子的字段和一个带有“操作”的工具栏,例如“保存”、“删除”、“取消”。
<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>
Our objective is to write the form in a way that doesn't require JavaScript, just plain old HTML form and submit buttons.
我们的目标是以不需要 JavaScript的方式编写表单,只需简单的旧 HTML 表单和提交按钮。
Since the action URL is defined in the Form tag and not in each individual submit button, our only option is to post to a generic URL and then start "if...then...else" to determine the name of the button that was submitted. Not very elegant, but our only choice, since we don't want to rely on JavaScript.
由于操作 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 LOBapplications 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.
唯一的问题是按下“删除”将提交服务器上的所有表单字段,即使此操作唯一需要的是带有 post-id 的隐藏输入。在这个小例子中没什么大不了的,但是我的LOB应用程序中有数百个(可以这么说)字段和选项卡的表单,(由于要求)必须一次性提交所有内容,无论如何这似乎非常低效和浪费。如果支持表单嵌套,我至少可以将“删除”提交按钮包装在它自己的表单中,只有 post-id 字段。
You may say "Just implement the "Delete" as a link instead of submit". This would be wrong in so many levels, but most importantly because Side-effect actions like "Delete" here, should never be a GET request.
您可能会说“只需将“删除”作为链接而不是提交”。这在很多层面上都是错误的,但最重要的是因为像“删除”这样的副作用操作永远不应该是一个 GET 请求。
So my question (particularly to those that say they haven't needed form nesting) is What do YOU do? Is there any elegant solution that I'm missing or the bottom line is really "Either require JavaScript or submit everything"?
所以我的问题(特别是那些说他们不需要表单嵌套的人)是你做什么?有没有我遗漏的优雅解决方案,或者底线真的是“要么需要 JavaScript 要么提交所有内容”?
采纳答案by One Crayon
I would implement this exactly as you described: submit everything to the server and do a simple if/else to check what button was clicked.
我会完全按照您的描述实现这一点:将所有内容提交到服务器并执行简单的 if/else 以检查单击了哪个按钮。
And then I would implement a Javascript call tying into the form's onsubmit event which would check before the form was submitted, and only submit the relevant data to the server (possibly through a second form on the page with the ID needed to process the thing as a hidden input, or refresh the page location with the data you need passed as a GET request, or do an Ajax post to the server, or...).
然后我将实现一个与表单的 onsubmit 事件相关联的 Javascript 调用,该调用将在提交表单之前进行检查,并且只将相关数据提交给服务器(可能通过页面上的第二个表单,其 ID 需要处理该事件作为一个隐藏的输入,或者使用您需要作为 GET 请求传递的数据刷新页面位置,或者向服务器执行 Ajax 发布,或者...)。
This way the people without Javascript are able to use the form just fine, but the server load is offset because the people who do have Javascript are only submitting the single piece of data needed. Getting yourself focused on only supporting one or the other really limits your options unnecessarily.
这样,没有 Javascript 的人可以很好地使用表单,但是服务器负载被抵消了,因为有 Javascript 的人只提交了所需的单个数据。让自己专注于只支持其中一个确实会不必要地限制您的选择。
Alternatively, if you're working behind a corporate firewall or something and everybody has Javascript disabled, you might want to do two forms and work some CSS magic to make it look like the delete button is part of the first form.
或者,如果您在公司防火墙或其他东西后面工作,并且每个人都禁用了 Javascript,您可能需要做两个表单并使用一些 CSS 魔法,使其看起来像删除按钮是第一个表单的一部分。
回答by shovavnik
I know this is an old question, but HTML5 offers a couple new options.
我知道这是一个老问题,但 HTML5 提供了几个新选项。
The first is to separate the form from the toolbar in the markup, add another form for the delete action, and associate the buttons in the toolbar with their respective forms using the form
attribute.
第一种是在标记中将表单与工具栏分开,为删除操作添加另一个表单,并使用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>
This option is quite flexible, but the original post also mentioned that it may be necessary to perform different actions with a single form. HTML5 comes to the rescue, again. You can use the formaction
attribute on submit buttons, so different buttons in the same form can submit to different URLs. This example just adds a clone method to the toolbar outside the form, but it would work the same nested in the form.
这个选项非常灵活,但原帖也提到可能需要用一个表单来执行不同的操作。HTML5 再次拯救了我们。您可以formaction
在提交按钮上使用该属性,因此同一表单中的不同按钮可以提交到不同的 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
http://www.whatwg.org/specs/web-apps/current-work/#attributes-for-form-submission
The advantage of these new features is that they do all this declaratively without JavaScript. The disadvantage is that they are not supported on older browsers, so you'd have to do some polyfilling for older browsers.
这些新功能的优势在于它们无需 JavaScript 即可声明式地完成所有这些工作。缺点是旧浏览器不支持它们,因此您必须对旧浏览器进行一些填充。
回答by Jason
can you have the forms side by side on the page, but not nested. then use CSS to make all the buttons line up pretty?
你可以在页面上并排放置表单,但不要嵌套。然后使用 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>
回答by Nishi
HTML5 has an idea of "form owner" - the "form" attribute for input elements. It allows to emulate nested forms and will solve the issue.
HTML5 有一个“表单所有者”的概念——输入元素的“表单”属性。它允许模拟嵌套表单并将解决问题。
回答by B.D.Joe
Kind of old topic, but this one might be useful for someone:
一种古老的话题,但这个话题可能对某人有用:
As someone mentioned above - you can use dummy form. I had to overcome this issue some time ago. At first I totally forgot about this HTML restriction and just added the nested forms. Result was interesting - I lost my first form from the nested. Then it turned out to be some kind of a "trick" to simply add a dummy form (that will be removed from the browser) before the actual nested forms.
正如上面提到的那样-您可以使用虚拟形式。前段时间我不得不克服这个问题。起初我完全忘记了这个 HTML 限制,只是添加了嵌套表单。结果很有趣 - 我从嵌套中丢失了我的第一个表单。然后结果证明在实际嵌套表单之前简单地添加一个虚拟表单(将从浏览器中删除)是某种“技巧”。
In my case it looks like this:
就我而言,它看起来像这样:
<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>
Works fine with Chrome, FireFox and Safari. IE up to 9 (not sure about 10) and Opera does not detect parameters in the main form. The $_REQUEST global is empty, regardless of the inputs. Inner forms seems to work fine everywhere.
适用于 Chrome、FireFox 和 Safari。IE 最多 9 个(不确定大约 10 个)和 Opera 不检测主窗体中的参数。无论输入如何,$_REQUEST 全局都是空的。内部形式似乎在任何地方都可以正常工作。
Haven't tested another suggestion described here - fieldset around nested forms.
还没有测试这里描述的另一个建议 - 围绕嵌套表单的字段集。
EDIT: Frameset didn't work! I simply added Main form after the others (no more nested forms) and used jQuery's "clone" to duplicate inputs in the form on button click. Added .hide() to each of the cloned inputs to keep layout unchanged and now it works like a charm.
编辑:框架集不起作用!我只是在其他表单之后添加了 Main 表单(不再是嵌套表单),并使用 jQuery 的“克隆”在按钮单击时复制表单中的输入。为每个克隆的输入添加了 .hide() 以保持布局不变,现在它就像一个魅力。
回答by AmbroseChapel
I think Jason's right. If your "Delete" action is a minimal one, make that be in a form by itself, and line it up with the other buttons so as to make the interface look like one unified form, even if it's not.
我认为杰森是对的。如果您的“删除”操作是最小的,请将其单独放在一个表单中,并将其与其他按钮对齐,以使界面看起来像一个统一的表单,即使它不是。
Or, of course, redesign your interface, and let people delete somewhere else entirely which doesn't require them to see the enormo-form at all.
或者,当然,重新设计您的界面,让人们完全删除其他地方,这根本不需要他们看到 enormo 形式。
回答by Ron Savage
One way I would do this without javascript would be to add a set of radio buttons that define the action to be taken:
我在没有 javascript 的情况下执行此操作的一种方法是添加一组定义要采取的操作的单选按钮:
- Update
- Delete
- Whatever
- 更新
- 删除
- 任何
Then the action script would take different actions depending on the value of the radio button set.
然后动作脚本将根据单选按钮集的值采取不同的动作。
Another way would be to put two forms on the page as you suggested, just not nested. The layout may be difficult to control though:
另一种方法是按照您的建议在页面上放置两个表单,而不是嵌套。布局可能难以控制:
<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>
Using the hidden "task" field in the handling script to branch appropriately.
使用处理脚本中隐藏的“任务”字段进行适当的分支。
回答by Rob Crowther
This discussion is still of interest to me. Behind the original post are "requirements" which the OP seems to share - i.e. a form with backwards compatibility. As someone whose work at time of writing must sometimes support back to IE6 (and for years to come), I dig that.
这个讨论对我来说仍然很有趣。原始帖子后面是 OP 似乎共享的“要求” - 即具有向后兼容性的表单。作为在撰写本文时的工作有时必须支持回 IE6(以及未来几年)的人,我深挖这一点。
Without pushing the framework (all organisations are going to want to reassure themselves on compatibility/robustness, and I'm not using this discussion as justification for the framework), the Drupal solutions to this issue are interesting. Drupal is also directly relevant because the framework has had a long time policy of "it should work without Javascript (only if you want)" i.e. the OP's issue.
在不推动框架的情况下(所有组织都希望在兼容性/健壮性方面让自己放心,我不会使用这个讨论作为框架的理由),这个问题的 Drupal 解决方案很有趣。Drupal 也直接相关,因为该框架长期以来一直有“它应该在没有 Javascript 的情况下工作(仅在您需要时)”的政策,即 OP 的问题。
Drupal uses it's rather extensive form.incfunctions to find the triggering_element (yes, that's the name in code). See the bottom of the code listed on the API page for form_builder(if you'd like to dig into details, source is recommended - drupal-x.xx/includes/form.inc). The builder uses automatic HTML attribute generation and, via that, can on return detect which button was pressed, and act accordingly (these can be set up to run separate processes too).
Drupal 使用相当广泛的form.inc函数来查找 triggering_element(是的,这就是代码中的名称)。请参阅form_builderAPI 页面上列出的代码底部 (如果您想深入了解详细信息,建议使用源代码 - drupal-x.xx/includes/form.inc)。构建器使用自动 HTML 属性生成,通过它,可以在返回时检测哪个按钮被按下,并采取相应的行动(这些也可以设置为运行单独的进程)。
Beyond the form builder, Drupal splits data 'delete' actions into separate urls/forms, likely for the reasons mentioned in the original post. This needs some sort of search/listing step (groananother form!, but is user-friendly) as a preliminary. But this has the advantage of eliminating the "submit everything" issue. The big form with the data is used for it's intended purpose, data creation/updating (or even a 'merge' action).
除了表单构建器之外,Drupal 将数据“删除”操作拆分为单独的 url/表单,可能是出于原始帖子中提到的原因。这需要某种搜索/列表步骤(呻吟另一种形式!,但对用户友好)作为初步。但这具有消除“提交所有内容”问题的优点。带有数据的大表单用于其预期目的,数据创建/更新(甚至“合并”操作)。
In other words, one way of working round the problem is to devolve the form into two, then the problem vanishes (and the HTML methods can be corrected through a POST too).
换句话说,解决问题的一种方法是将表单分解为两个,然后问题就消失了(HTML 方法也可以通过 POST 来纠正)。
回答by scotweb
My solution is to have the buttons call JS functions which write and then submit forms outwith the main form
我的解决方案是让按钮调用 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>
回答by Dan Rosenstark
Use an iframe
for the nested form. If they need to share fields, then... it's not really nested.
iframe
对嵌套表单使用 an 。如果他们需要共享字段,那么......它并不是真正的嵌套。