【问题标题】:FormData() object does not add submit-type inputs from form, while on FirefoxFormData() 对象不会从表单添加提交类型的输入,而在 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 等......),它会被覆盖,如果它不存在,它就会被创建。

问题

  1. 类似的 - 你有没有遇到过类似的事情?
  2. 修复 - 我认为我的解决方案是 hack,您有什么更好的修复方法吗?

【问题讨论】:

  • 这是预期的行为。提交按钮只有在表单正常提交时才会自动发送。当您在 Javascript 中创建 FormData 时,它不知道提交与特定的提交按钮相关,因此它无法将其自动添加到 FormData。我很惊讶它在其他浏览器中的工作方式不同。
  • 很抱歉,我不同意你的观点。文档中没有任何地方这么说。你可能是对的,但在我看到实际证据之前,我仍然相信这不是预期的行为。请参阅:developer.mozilla.org/en-US/docs/Web/API/FormDatadeveloper.mozilla.org/en-US/docs/Web/API/FormData/…
  • 我刚刚看到 Chrome 58 出现这种行为的页面,而使用 Chrome 53 的同事“很好”。也就是说,从表单创建了一个新的 FormData 对象,而我的不包括提交者,而他的包含。非常令人沮丧,因为表单上有几个提交按钮,它们有自己的名称和值。

标签: javascript forms firefox xmlhttprequest form-data


【解决方案1】:

根据 WHATWG 规范,FireFox 似乎是正确的。

FormData 构造函数的 XMLHttpRequest 规范说:

  1. 如果给定了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);
});

如果有人需要使用输入类型提交可以添加上面的代码,我们在这种情况下使用按钮:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    • 2010-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-24
    • 2016-09-30
    相关资源
    最近更新 更多