FormData不包括按钮的值。

18

考虑以下代码片段:

$('#myBtn').click(function(e) {
    e.preventDefault();
    
    var formElement = $(this).closest('form')[0];
    var request = new XMLHttpRequest();
    request.open("POST", "https://posttestserver.com/post.php");
    request.send(new FormData(formElement));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form method="POST" action="https://posttestserver.com/post.php">
  <input type="text" name="wtf" />
  <button type="submit" name="lol" value="cats" id="myBtn">
    Huh
  </button>
</form>

(打开您的开发人员工具并观察HTTP请求。)

当您单击按钮时,文本框中输入的任何文本都包含在POST请求中。但是,来自按钮本身的lol=cats对不包括在内。

我如何使 FormData包括按钮提供的数据?


按钮不是输入类型,因此无法将值传递给POST请求。 - Saurabh Mistry
1
你在Firefox中进行测试吗?请查看此问题:https://dev59.com/TFoT5IYBdhLWcg3wrRKE - Rory McCrossan
@RoryMcCrossan: 接受的答案似乎准确描述并解释了这里正在发生的事情。 - Lightness Races in Orbit
我确实将其关闭为重复问题,但意识到它可能不再是一个仅限于Firefox的问题,所以重新打开了 :) - Rory McCrossan
@RoryMcCrossan:Barmar引用了解释此事的规范——认为重复是可以接受的。 - Lightness Races in Orbit
显示剩余2条评论
5个回答

13
因为调用 FormData 构造函数的代码并不知道它是由哪个提交按钮触发的(更不用说是哪个提交按钮了),而且你只想要被使用的提交按钮的值被包含在提交的数据中,所以该提交按钮不会被包含在提交的数据中。你可以使用 FormData.append 来包含希望的键值对。

$('#myBtn').click(function(e) {
    e.preventDefault();
    var formElement = $(this).closest('form')[0];
    var formData = new FormData(formElement);
    formData.append("lol","cats");
    var request = new XMLHttpRequest();
    request.open("POST", "https://posttestserver.com/post.php");
    request.send(formData);
});
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
 <form method="POST" action="https://posttestserver.com/post.php">
      <input type="text" name="wtf" />
      <button type="submit" id="myBtn">
        Huh
      </button>
    </form>


哦,是的,因为 FormData 构造函数不知道我按了哪个按钮 :D - Lightness Races in Orbit
隐藏输入框需要根据我点击的按钮动态填充正确的值,但我想现在这是一个不同的任务。 - Lightness Races in Orbit
实际上在我的情况下,这是最好的方法,因为点击处理程序确实是一个ajaxSubmitForm函数,在我的应用程序中适用于所有表单,但对于这个例子是的 :) - Lightness Races in Orbit

8

正如你已经提到的那样,FormData无法知道按钮的名称。但是当你捕获表单提交时,可以通过事件的submitter属性获取名称:

const form = document.querySelector("form")

form.addEventListener("submit", ev => {
    ev.preventDefault()

    const data = {}

    for (const field of new FormData(form)) {
        data[field[0]] = field[1]
    }

    // NB: we are setting "none" as a fallback in case the form
    // has been submitted without clicking a button, e.g. by 
    // hitting enter in an input field.

    data.action = ev.submitter ? ev.submitter.name : "none"

    // … and so on
})

请注意,截至2021年4月,submitter不受Safari(桌面或移动版)支持,如果您需要支持所有主要浏览器,则这是一个较差的选择。 - justanotherprogrammer
谢谢您提供这个信息,我之前不知道。您有什么建议可以替代它吗? - lxg
我不知道。我一直在努力寻找解决我遇到的问题的方法,我还以为这是一个很好的解决方案,直到我在Safari中进行了测试 :( - justanotherprogrammer
1
根据 https://bugs.webkit.org/show_bug.cgi?id=229660,一个补丁已经发布了,但是还没有在 Safari 中更新。 - boxed
根据 mdn 的说法,Safari 15.4 将提供完整支持,但是全球仅有 74% 的完整支持,这是根据 can_i_use 的数据统计得出的。 - raphael

4

如果我在 Safari 中执行 new FormData(event.target),我会得到按钮数据。但是在 Chrome 中不会得到。在 Safari 中,event.submitter 总是为 none,但在 Chrome 中却有效。因此,如果我只是这样做:

let data = new FormData(event.target);
if (event.submitter) {
    data.append(event.submitter.name, event.submitter.value)
}
然后我在Safari和Chrome中都得到了期望的行为。

1
规范已更新以支持FormData传递submitter, 该功能在主流浏览器的最新版本中可用 (Chrome, Firefox, Safari)。对于不支持它的浏览器,您可以使用formdata-submitter-polyfill包。这样,您就可以可靠地创建与等效本机表单提交相匹配的FormData对象(即,如果适用,则包括提交按钮的条目)。 在提交处理程序中的基本用法如下:
myform.addEventListener("submit", (e) => {
  e.preventDefault();
  const formData = new FormData(e.target, e.submitter);
  // do something with formData...
});

根据您的浏览器版本,您可能还需要使用event-submitter-polyfill包,以确保在SubmitEvent上设置submitter属性。


-1
你只需要添加一个隐藏的输入类型元素。你会看到键值lol:cats会附加在有效负载中。

$('#myBtn').click(function(e) {
    e.preventDefault();
    
    var formElement = $(this).closest('form')[0];
    var request = new XMLHttpRequest();
    request.open("POST", "https://posttestserver.com/post.php");
    request.send(new FormData(formElement));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form method="POST" action="https://posttestserver.com/post.php">
  <input type="text" name="wtf" />
  <input type="hidden" name="lol" value="cats" />
  <button type="submit" id="myBtn">
    Huh
  </button>
</form>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,