marioizquierdo / jquery.serializeJSON

Serialize an HTML Form to a JavaScript Object, supporting nested attributes and arrays.
MIT License
1.71k stars 435 forks source link

Problem with names with array-style numerical keys #12

Closed joshuajabbour closed 10 years ago

joshuajabbour commented 10 years ago

Say you've got a form like:

<form>
    <input type="hidden" name="status[1]" value="1">
    <input type="hidden" name="status[3]" value="0">
    <input type="hidden" name="status[6]" value="1">
</form>

$('form').serializeJSON() gives you:

{
    "status": [ // Array[3]
        1: "1",
        3: "0",
        6: "1"
    ]
}

which on many backends will get converted into a non-associative array, delinking the keys. This means you can't use things like IDs as keys.

However, both https://github.com/danheberden/jquery-serializeForm and https://github.com/serbanghita/formToObject.js get this right, and $('form').serializeForm() gives you:

{
    "status": { // Object
        "1": "1",
        "3": "0",
        "6": "1"
    }
}

IMO, anytime an explicit value is given in the form array-syntax, that element should be an object. So given status[1], status would be an object, whereas given status[], status would be an array.

marioizquierdo commented 10 years ago

Well, I first looked at this issue and thought "Sorry, expected behavior ..."

But then I played with Rails to see what was the behavior of those parameter names, and realize that the current Rack parse_nested_query method is actually doing what you suggest. And what jquery.serializeJSON is supposed to do is to mimmic that behavior. Then you found a bug. Thanks!

I will change the behavior of this when I have some time and release a new API-breaking version (1.3.0)

marioizquierdo commented 10 years ago

I just released version 2.0.0 with the changes that resolve this issue.

The new default parsing will treat integer keys as object attributes by default.

<form>
  <input type="text" name="arr[0]" value="foo"/>
  <input type="text" name="arr[1]" value="var"/>
  <input type="text" name="arr[5]" value="inn"/>
</form>
$('form').serializeJSON(); // version 2.0.0
// returns => {'arr': {'0': 'foo', '1': 'var', '5': 'inn' }}

But to keep backwards compatibility, I added an option useIntKeysAsArrayIndex:

$('form').serializeJSON({useIntKeysAsArrayIndex: true}); // version 2.0.0
// returns => {'arr': ['foo', 'var', undefined, undefined, undefined, 'inn']}

that behaves like before:

$('form').serializeJSON(); // version <= 1.3.0
// returns => {'arr': ['foo', 'var', undefined, undefined, undefined, 'inn']}