8
\$\begingroup\$

I'm sending data from a form with a variable number of fields via an Ajax call. Some of the fields are grouped together so I have opted to send them as an array of JSON objects to keep the groupings, but there are a number of ways of doing this. For client-side, is it better to read the form as JavaScript objects and stringify them or just directly work with strings from the start?

Here's an example:

I want to group the data so I know which date goes with which member, so I have created a bunch of objects and added them to an array. This seems to work but there are issues with using JSON.stringify because it's not supported in IE7. I don't know if modifying the form is very efficient either. How would you manage this? Or would you submit the form as is and sort it out on the server? What's the most widely accepted approach?

HTML:

<form id="form">
    <h3>Group Name</h3>
    <input type="text" name="group_name"><br>
    <h3>Members</h3>
    <button type="button">New member</button>
    <br><label for="name">Name</label><label for="date">Date</label>
    <div id="dynamic_form">
        <span class="member_data"><input type="text" name="name"><input type="text" name="date"></span><br>
    </div>
    <input type="submit">
</form>
<div id="member_info"></div>

JavaScript:

$(document).ready(function(){       
    $('#form').submit(function(e){
        var memberArr = [];
        $('.member_data').each(function(){
            var thisMember = {};
            $(this).children().each(function(){
                thisMember[$(this).attr('name')] = $(this).val();
            });
            memberArr.push(thisMember);
            // Delete this input
            $(this).remove();
        });

        var input = $("<input>").attr("type", "hidden").attr("name", "members").val(JSON.stringify(memberArr));
        $('#dynamic_form').append($(input));
        e.preventDefault();

        $.post("http://geraintanderson.com/cgi-bin/ajax_array.py",
        $('#form').serialize(),
        function(data, status){
            $('#member_info').html(data);
            // Reset the form
            $('#dynamic_form').html('<span class="member_data"><input type="text" name="name"><input type="text" name="date"></span><br>');
        });
    });

    $('button').click(function(){
        // Add new form fields
        $('#dynamic_form').append('<span class="member_data"><input type="text" name="name"><input type="text" name="date"></span><br>');
    });
});

And here's a live example using a Python script to return some text.

\$\endgroup\$
5
\$\begingroup\$

First of all, I'd make sure that supporting IE7 is actually required. It's a really old browser by now, and there are a lot of things that are much more difficult to do.

Anyway, as for sending multiple form values, there's a common - but informal - way of doing that without JSON. It's supported by some server-side languages/frameworks (notably PHP, where I think it started), so it might work for you.

It's all about naming your inputs using square brackets to namespace them.

Typically - again, this isn't a true standard, just an informal one - you would use a name like foo[bar] to specify that bar is a named sub-property of foo. Or you'd use the name foo[] multiple times to indicate that foo is an array (but this only works for plain value arrays).

Here, you need a little of both, something like this (I've skipped a lot of HTML just to make it clearer):

<form id="form">
    <input type="text" name="group_name">

    <div id="dynamic_form">
        <input type="text" name="members[0][name]">
        <input type="text" name="members[0][date]">

        <input type="text" name="members[1][name]">
        <input type="text" name="members[1][date]">

        <input type="text" name="members[2][name]">
        <input type="text" name="members[2][date]">
    </div>
</form>

E.g. what gets sent to the server would be something like:

group_name=SomeGroup
members[0][name]=Alice
members[0][date]=01/01/2015
members[1][name]=Bob
members[1][date]=02/01/2015
members[2][name]=Carol
members[2][date]=03/01/2015

This is roughly equivalent to a JSON structure like:

{
  "group_name": "SomeGroup",
  "members": [
    {
      "name": "Alice",
      "date": "01/01/2015"
    },
    {
      "name": "Bob",
      "date": "02/01/2015"
    },
    {
      "name": "Carol",
      "date": "03/01/2015"
    },
  ]
}

Again, I can't guarantee that how your server will understand it, but it's a common way to do things.

Even if your server-side code doesn't understand it automagically, it's still parseable; you just have to write a bit more code yourself.

The trick is of course to increment the number, when you add new fields. That can be done in many ways, though.

Alternatively, you simply name all your fields the same:

<input type="text" name="name">
<input type="text" name="date">
<input type="text" name="name">
<input type="text" name="date">
<input type="text" name="name">
<input type="text" name="date">

The browser will send all the values, but usually the server-side software has a rule for how to handle duplicate names, and keeps only the first or last one it sees. But again, you can access the raw request data, and parse it yourself, if you want. But there's a lot of work in doing that.

On a side-note: I'd avoid having duplication between the javascript and the HTML (right now, the page starts out with 1 set of member inputs in the HTML, and the rest get added using a string in the JavaScript. That means you have to keep both of them identical in order for things to work - not great.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.