FormData() 对象不会从表单添加提交类型的输入,而在 Firefox 上
Posted
技术标签:
【中文标题】FormData() 对象不会从表单添加提交类型的输入,而在 Firefox 上【英文标题】:FormData() object does not add submit-type inputs from form, while on Firefox 【发布时间】:2016-11-11 16:28:18 【问题描述】:今天我遇到了一个有趣的错误,花了很多时间才弄清楚。
设置
页面上的表单。提交时,数据被捕获并用它创建new FormData()
对象。
该对象通过 xhr
请求发送到 .php
脚本,然后返回 ok
/ error
消息。
代码看起来像这样:(简化版,不需要绒毛)
<form name="frm" id="frm" action="" method="post" onsubmit="save(event, this);" enctype="multipart/form-data">
<input name="name" id="name" type="text" value="..." />
<input name="email" id="email" type="text" value="..." />
<input name="phone" id="phone" type="text" value="..." />
<input name="website" id="website" type="text" value="..." />
<textarea name="details" id="details"></textarea>
<input name="send" type="submit" value="Send" />
</form>
<script type="text/javascript">
function save(e, frm)
if (document.getElementById('nume').value == '' ||
document.getElementById('email').value == '' ||
document.getElementById('telefon').value == '' ||
document.getElementById('site').value == '')
alert('Forms empty');
else
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
xhr.onreadystatechange = function ()
if (xhr.readyState == 4)
var r = JSON.parse(xhr.responseText);
if (r.code == 0)
document.getElementById('message_ok').style.display = 'block';
else
document.getElementById('message_err').style.display = 'block';
;
xhr.open('POST', 'http://url', true);
var data = new FormData(frm);
xhr.send(data);
e.preventDefault();
</script>
将此发送到.php
将生成一个如下所示的数组:
Array
(
[name] => some name
[email] => some email
[phone] => 11111111
[website] => some site
[details] => some details
[send] => Send
)
而.php
将回复"message":"ok","code":0
或"message":"error","code":1
现在这是预期的行为。这是我在 Chrome、IE 或 Safari 上得到的。
问题
然而,在 Firefox 上,我得到相同的数组,但没有 submit
输入 (name="send"
) 键/值对:
Array
(
[name] => some name
[email] => some email
[phone] => 11111111
[website] => some site
[details] => some details
)
我在 Linux 和 Windows 上都试过了,以覆盖我的基础,但它仍然给出了同样不令人满意的结果。
解决方案
在网上搜索并出现空白后,我解决它的方法(更多的补丁,而不是真正解决)是覆盖send
键/值:
var data = new FormData(frm);
data.append('send', 'Send');
xhr.send(data);
这是可行的,因为如果它已经定义(Chrome 等......),它会被覆盖,如果它不存在,它就会被创建。
问题
-
类似的 - 你有没有遇到过类似的事情?
修复 - 我认为我的解决方案是 hack,您有什么更好的修复方法吗?
【问题讨论】:
这是预期的行为。提交按钮只有在表单正常提交时才会自动发送。当您在 Javascript 中创建FormData
时,它不知道提交与特定的提交按钮相关,因此它无法将其自动添加到 FormData
。我很惊讶它在其他浏览器中的工作方式不同。
很抱歉,我不同意你的观点。文档中没有任何地方这么说。你可能是对的,但在我看到实际证据之前,我仍然相信这不是预期的行为。请参阅:developer.mozilla.org/en-US/docs/Web/API/FormData 和 developer.mozilla.org/en-US/docs/Web/API/FormData/…
我刚刚看到 Chrome 58 出现这种行为的页面,而使用 Chrome 53 的同事“很好”。也就是说,从表单创建了一个新的 FormData 对象,而我的不包括提交者,而他的包含。非常令人沮丧,因为表单上有几个提交按钮,它们有自己的名称和值。
【参考方案1】:
根据 WHATWG 规范,FireFox 似乎是正确的。
FormData
构造函数的 XMLHttpRequest
规范说:
如果给定了
form
,则将fd
的条目设置为constructing the form data set 的结果form
。
那么在构造表单数据集的描述中,是这样说的:
在提交者submitter 的上下文中form 可选地构造表单数据集 的算法如下。如果没有另外指定,提交者为空。
表单中的按钮只有在提交者的情况下才会包含在表单数据集中。但是当这个算法从FormData
构造函数中执行时,没有指定提交者,所以表单数据集中不应该包含任何按钮。
【讨论】:
过失!我猜你一直都是对的。感谢您提供规格的链接,因此我可以提供一些可靠的证据。附带说明:令人恐惧的是,有多少浏览器实现了不符合规范的功能。 即使在submit
处理程序中调用了FormData
,Chrome 似乎也错过了按钮。在这种情况下,event.submitter
确实包含对正确按钮的引用,但 Chrome 仍然没有将其包含在 FormData
中。
这是预期的行为。 FormData
构造函数没有接收event
作为参数,所以它不知道event.submitter
是什么。该按钮仅包含在默认的表单提交代码中。【参考方案2】:
在 Chrome 58 中遇到类似情况。
在我的问题中,有多个提交按钮,我需要知道选择了哪一个,或者至少知道是否选择了一个特定的按钮。
我可怕的 hack 是显式监听该按钮被选中,创建一个隐藏的输入并将其插入到提交按钮之前。
更新:改进的黑客攻击
监听提交按钮的点击,并通过按钮作为提交者发送到 on('submit'),并在 ajax 调用中使用之前附加到 FormData 对象。
根据输入[type="submit"] 进行修改,并可能对submitter
的内容进行额外的错误检查。
$('#defaultModalObject-1').on('click', 'button[type="submit"]', function(event)
/* horrible hack to detect wizard_goto_step submissions via ajax */
event.preventDefault();
$(event.target.form).trigger('submit', event.target);
);
$('#defaultModalObject-1').on('submit', 'form', function(event, submitter)
...
var formdata = new FormData(form[0]);
if (submitter != undefined)
formdata.append(submitter.name, submitter.value);
...
);
原始黑客
$('#ajax_form_modal_result').on('click', 'button[type="submit"][name="wizard_goto_step"]', function(event)
/* horrible hack to detect wizard_goto_step submissions via ajax */
event.preventDefault();
var input = $('input[type="hidden"]').attr('name', 'wizard_goto_step').val(event.target.value);
$(event.target).before(input);
$(event.target.form).trigger('submit');
);
很遗憾,我的委托表单处理程序 $('#defaultModalObject-1').on('submit', 'form', function(event) ... );
上没有创建者信息
【讨论】:
哪个,顺便说一句,似乎仍然不起作用。当我得到一些工作代码时,我会编辑我的答案。【参考方案3】:我们在 linux 客户端上遇到同样的问题,使用下面的代码将所有按钮元素添加到我们的表单数据中。
第一个问题是在某些代码中获取表单数据时出错
if($this.is('form'))
var fd = new FormData($this.get(0));
else
var fd = new FormData();
第二个问题类似于以 ajax 形式添加按钮的问题。有时我们在一个表单中有多个按钮,并且想要检测按下了哪个按钮。
$this.find('button').each(function()
fd.append(this.getAttribute('name'), this.value);
);
如果有人需要使用输入类型提交可以添加上面的代码,我们在这种情况下使用按钮:)
【讨论】:
以上是关于FormData() 对象不会从表单添加提交类型的输入,而在 Firefox 上的主要内容,如果未能解决你的问题,请参考以下文章
从javascript函数创建的表单提交FormData到php