FormData не включает значение кнопок

Рассмотрим следующий фрагмент:

$('#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 включать данные, заданные кнопками ?


person Lightness Races in Orbit    schedule 18.01.2018    source источник
comment
Кнопка не является типом ввода, поэтому она не может передать значение POST-запросу.   -  person Saurabh Mistry    schedule 18.01.2018
comment
Вы тестируете в Firefox? Проверьте этот вопрос: stackoverflow.com/questions/38277900/   -  person Rory McCrossan    schedule 18.01.2018
comment
@RoryMcCrossan: Chrome, но то же самое в FF   -  person Lightness Races in Orbit    schedule 18.01.2018
comment
@RoryMcCrossan: Принятый ответ, кажется, точно описывает и объясняет, что здесь происходит.   -  person Lightness Races in Orbit    schedule 18.01.2018
comment
В этом случае возможно, что другие браузеры обновились, чтобы следовать стандарту. Честно говоря, я всегда находил поддержку отправки значения кнопки отправки в запросе немного ненадежной. Я бы добавил его в запрос вручную, если это возможно.   -  person Rory McCrossan    schedule 18.01.2018
comment
Я закрыл его как обман, но понял, что это больше не может быть конкретной проблемой Firefox, поэтому снова открыл :)   -  person Rory McCrossan    schedule 18.01.2018
comment
@RoryMcCrossan: Бармар процитировал спецификацию, которая объясняет это - думаю, что обман в порядке   -  person Lightness Races in Orbit    schedule 18.01.2018


Ответы (2)


Поскольку вызов конструктора 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>

person lucky    schedule 18.01.2018
comment
Ах да, потому что конструктор FormData не знает, какую кнопку я нажал :D - person Lightness Races in Orbit; 18.01.2018
comment
Скрытый ввод должен будет динамически заполняться правильным значением в зависимости от того, какую кнопку я нажал, но я полагаю, что теперь это другая задача. - person Lightness Races in Orbit; 18.01.2018
comment
На самом деле в моем случае это лучший способ, поскольку обработчик кликов на самом деле является функцией ajaxSubmitForm, общей для всех форм в моем приложении, но для этого примера да :) - person Lightness Races in Orbit; 18.01.2018

Как вы уже сказали, 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
})
person lxg    schedule 26.12.2020
comment
Обратите внимание, что по состоянию на апрель 2021 года submitter НЕ поддерживается Safari (настольным или мобильным), что делает его плохим вариантом, если вам нужна поддержка всех основных браузеров. - person justanotherprogrammer; 02.04.2021
comment
Спасибо за эту информацию, я этого не знал. У вас есть предложение, что мы могли бы использовать вместо этого? - person lxg; 02.04.2021
comment
Я не делаю. Я боролся, пытаясь найти решение проблемы, с которой я столкнулся, и также думал, что это отличное решение, пока не протестировал в Safari :( - person justanotherprogrammer; 02.04.2021