最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - FormData() object does not add submit-type inputs from form, while on Firefox - Stack Overflow

programmeradmin4浏览0评论

Today I came across an interesting bug, which took a good chunk of time to get to the bottom of.

The setup

A form on a page. On submit, the data gets captured and new FormData() object gets created with it.

That object gets sent with and xhr request to an .php script, which then returns an ok / error message.

The code looks something like this: (simplified version, no need for fluff)

<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>

Sending this to .php will result in an array which kind of looks like this:

Array
(
    [name] => some name
    [email] => some email
    [phone] => 11111111
    [website] => some site
    [details] => some details
    [send] => Send
)

and .php will respond with either {"message":"ok","code":0} or {"message":"error","code":1}

Now this is the expected behavior. This is what I get on either Chrome, IE or Safari.

The problem

On Firefox however, I get the same array except without the submit input (name="send") key/value pair:

Array
(
    [name] => some name
    [email] => some email
    [phone] => 11111111
    [website] => some site
    [details] => some details
)

I tried on both Linux and Windows, to cover my basis, yet it still gave the same unsatisfying result.

Solution

After searching online and coming up empty, the way I solved it (more of patching, not really solving) was to overwrite the send key/value:

var data = new FormData(frm);
data.append('send', 'Send');
xhr.send(data);

This works, because if it's already defined (Chrome, etc...) it gets overwritten, if it doesn't exist, it gets created.

Questions

  1. Similar - Have you ever faced something similar?
  2. Fix - I consider my solution a hack, have you got any ideas for a better fix?

Today I came across an interesting bug, which took a good chunk of time to get to the bottom of.

The setup

A form on a page. On submit, the data gets captured and new FormData() object gets created with it.

That object gets sent with and xhr request to an .php script, which then returns an ok / error message.

The code looks something like this: (simplified version, no need for fluff)

<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>

Sending this to .php will result in an array which kind of looks like this:

Array
(
    [name] => some name
    [email] => some email
    [phone] => 11111111
    [website] => some site
    [details] => some details
    [send] => Send
)

and .php will respond with either {"message":"ok","code":0} or {"message":"error","code":1}

Now this is the expected behavior. This is what I get on either Chrome, IE or Safari.

The problem

On Firefox however, I get the same array except without the submit input (name="send") key/value pair:

Array
(
    [name] => some name
    [email] => some email
    [phone] => 11111111
    [website] => some site
    [details] => some details
)

I tried on both Linux and Windows, to cover my basis, yet it still gave the same unsatisfying result.

Solution

After searching online and coming up empty, the way I solved it (more of patching, not really solving) was to overwrite the send key/value:

var data = new FormData(frm);
data.append('send', 'Send');
xhr.send(data);

This works, because if it's already defined (Chrome, etc...) it gets overwritten, if it doesn't exist, it gets created.

Questions

  1. Similar - Have you ever faced something similar?
  2. Fix - I consider my solution a hack, have you got any ideas for a better fix?
Share Improve this question asked Jul 9, 2016 at 3:11 481b8423202598ecfb233c5fa68caf481b8423202598ecfb233c5fa68caf 1031 silver badge6 bronze badges 3
  • This is the expected behavior. Submit buttons are only sent automatically when the form is submitted normally. When you create the FormData in Javascript, it doesn't know that the submission is related to a particular submit button, so it can't add that automatically to the FormData. I'm very surprised it works differently in the other browsers. – Barmar Commented Jul 9, 2016 at 4:00
  • I'm sorry but I disagree with you. Nowhere in the documentation does it say that. You may be right, but until I see actual proof, I still believe this is not the expected behaviour. See: developer.mozilla.org/en-US/docs/Web/API/FormData and developer.mozilla.org/en-US/docs/Web/API/FormData/… – 481b8423202598ecfb233c5fa68caf Commented Jul 9, 2016 at 11:20
  • I've just come across a page where Chrome 58 is exhibiting this behaviour, and a colleague who is using Chrome 53 is "fine". This is, a new FormData object is getting created from a form, and mine does not include the submitter, and his does. Very frustrating, because there are several submit buttons with their own name and values on the form. – Reuben Commented Jun 19, 2017 at 6:19
Add a comment  | 

4 Answers 4

Reset to default 12

FireFox seems to be correct, according to the WHATWG specification.

The XMLHttpRequest specification of the FormData constructor says:

  1. If form is given, set fd's entries to the result of constructing the form data set for form.

Then in the description of constructing the form data set, it says:

The algorithm to construct the form data set for a form form optionally in the context of a submitter submitter is as follows. If not specified otherwise, submitter is null.

A button in the form is only included in the form data set if it's the submitter. But when this algorithm is executed from the FormData constructor, no submitter is specified, so no buttons should be included in the form data set.

Facing a similar thing in Chrome 58.

In my issue, there are multiple submit buttons, and I need to know which one was selected, or at least if a specific one was selected.

My horrible hack is to explicitly listen for that button being selected, create a hidden input and insert it before the submit button.

Updated: Improved hack

Listen for clicks of submit buttons and send through the button as the submitter to the on('submit'), and append to the FormData object before using it in the ajax call.

Modify to taste for input[type="submit"], and perhaps extra error checking on the content of 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);
    }
    ...
});

Original Hack

$('#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');
});

Unfortunately, the originator information is not available on my delegated form handler $('#defaultModalObject-1').on('submit', 'form', function(event) { ... });

We have same problem on linux clients and use below code to add all button elements into our formdata.

First problem is error on getting form data in some coditions

if($this.is('form'))
{
  var fd = new FormData($this.get(0));
}
else
{
  var fd = new FormData();
}

Second problem is like question to add button in ajax form. sometimes we have more than button in one form and want to detect which one is pressed.

$this.find('button').each(function()
{
  fd.append(this.getAttribute('name'), this.value);
});

If someone need to use input type submit can add like above code, we use button in this conditions:)

The spec was updated to support passing a submitter to FormData, and the feature is available in the latest version of major browsers (Chrome, Firefox, Safari). For browsers that don't support it, you can use the formdata-submitter-polyfill package. This way you can reliably create FormData objects that match equivalent native form submissions (i.e. including the submit button's entry(s), if appropriate).

The basic usage in a submit handler would then look something like this:

myform.addEventListener("submit", (e) => {
  e.preventDefault();
  const formData = new FormData(e.target, e.submitter);
  // do something with formData...
});

Depending on which browser versions you're targeting, you might want to use the event-submitter-polyfill package as well, which ensures the submitter property is set on SubmitEvent.

发布评论

评论列表(0)

  1. 暂无评论