fabian-hiller / decode-formdata

Decodes complex FormData into a JavaScript object
MIT License
241 stars 7 forks source link

Multiple entries with same name should turn into array #8

Closed micha149 closed 11 months ago

micha149 commented 11 months ago

Hey!

I just noticed that handling multiple entries with the same name will result in a single prop with the last value. Coming from plain ol HTML forms, I would expect that they turn into an array.

This situation occurs when I have multiple checkboxes with the same name, or (more problematic) a multi select:

<form id="myForm">
    <input type="checkbox" name="pets" value="cat" />
    <input type="checkbox" name="pets" value="dog" />
    <input type="checkbox" name="pets" value="pig" />

    <select name="colors" multiple>
        <option>Blue</option>
        <option>Red</option>
        <option>Gold</option>
    </select>
</form>
const formData = new FormData($('#myForm'));

Array.from(formData);
// [
//     ['pets', 'cat']
//     ['pets', 'dog']
//     ['colors', 'Red']
//     ['colors', 'Gold']
// ]

decode(formData, { arrays: ['pets', 'colors'] })
// {
//     pets: 'dog',
//     colors: 'Gold'
// }

I would expect to receive an array, if the same key is found multiple times, regardless if it's defined in the FormDataInfo or not. But the info need to be configured properly, to enforce receiving an array, if only a single value is selected, as we can not differentiate it from single value entries.

What do you think?

fabian-hiller commented 11 months ago

Thank you for cresting this issue. I will look into this and get back to you in the next few days.

fabian-hiller commented 11 months ago

You are right. This functionality was missing in v0.4.0. I fixed it in v0.5.0. Thanks for the hint. To be consistent and allow decode to return valid data even if no option is selected (empty array), the field must be specified in FormDataInfo.

micha149 commented 11 months ago

Thanks a lot! Works as expected now!

allow decode to return valid data even if no option is selected

It is also required to define arrays in FormDataInfo if only a single option is checked, because we can not differentiate from a single text field.

sacrosanctic commented 11 months ago

Can documentation be provided for this?

fabian-hiller commented 11 months ago

Yes, I will improve the documentation from time to time as more people start using the library. Basically, you just need to specify each array in the info argument of decode. Is there anything specific you want to know?

sacrosanctic commented 11 months ago
 test('should decode non-indexed arrays', () => {
    const formData = new FormData();
    formData.append('array', 'index_0');
    formData.append('array', 'index_1');
    formData.append('array', 'index_2');
    expect(
      decode(formData, {
        arrays: ['array'],
      })
    ).toEqual({
      array: ['index_0', 'index_1', 'index_2'],
    });
  });

Thanks, but I found a relevant test for what I'm looking for. It wasn't very clear to me what was the required templating from the above thread.

fabian-hiller commented 11 months ago

Here is a sample code that is clearer and shows both cases:

// Create form data
const formData = new FormData();

// Add values for `foo` array (without index)
formData.append('foo', 'index_0');
formData.append('foo', 'index_1');

// Add values for `bar` array (with index)
formData.append('bar.0', 'index_0');
formData.append('bar.1', 'index_0');

// Decode form data
const data = decode(formData, {
  arrays: ['foo', 'bar'], // both is required here
});