I had the same problem lately and came out with this .toJSON jQuery plugin which converts a form into a JSON object with the same structure. This is also expecially useful for dynamically generated forms where you want to let your user add more fields in specific places.
The point is you may actually want to build a form so that it has a structure itself, so let's say you want to make a form where the user inserts his favourite places in town: you can imagine this form to represent a <places>...</places>
XML element containing a list of places the user likes thus a list of <place>...</place>
elements each one containing for example a <name>...</name>
element, a <type>...</type>
element and then a list of <activity>...</activity>
elements to represent the activities you can perform in such a place. So your XML structure would be like this:
<places>
<place>
<name>Home</name>
<type>dwelling</type>
<activity>sleep</activity>
<activity>eat</activity>
<activity>watch TV</activity>
</place>
<place>...</place>
<place>...</place>
</places>
How cool would it be to have a JSON object out of this which would represent this exact structure so you'll be able to either:
- Store this object as it is in any CouchDB-like database
- Read it from your $_POST[] server side and retrive a correctly nested array you can then semantically manipulate
- Use some server-side script to convert it into a well-formed XML file (even if you don't know its exact structure a-priori)
- Just somehow use it as it is in any Node.js-like server script
OK, so now we need to think how a form can represent an XML file.
Of course the <form>
tag is the root
, but then we have that <place>
element which is a container and not a data element itself, so we cannot use an input tag for it.
Here's where the <fieldset>
tag comes in handy! We'll use <fieldset>
tags to represent all container elements in our form/XML representation and so getting to a result like this:
<form name="places">
<fieldset name="place">
<input type="text" name="name"/>
<select name="type">
<option value="dwelling">Dwelling</option>
<option value="restoration">Restoration</option>
<option value="sport">Sport</option>
<option value="administrative">Administrative</option>
</select>
<input type="text" name="activity"/>
<input type="text" name="activity"/>
<input type="text" name="activity"/>
</fieldset>
</form>
As you can see in this form, we're breaking the rule of unique names, but this is OK because they'll be converted into an array of element thus they'll be referenced only by their index inside the array.
At this point you can see how there's no name="array[]"
like name inside the form and everything is pretty, simple and semantic.
Now we want this form to be converted into a JSON object which will look like this:
{'places':{
'place':[
{
'name': 'Home',
'type': 'dwelling',
'activity':[
'sleep',
'eat',
'watch TV'
]
},
{...},
{...}
]
}}
To do this I have developed this jQuery plugin here which someone helped optimizing in this Code Review thread and looks like this:
$.fn.toJSO = function () {
var obj = {},
$kids = $(this).children('[name]');
if (!$kids.length) {
return $(this).val();
}
$kids.each(function () {
var $el = $(this),
name = $el.attr('name');
if ($el.siblings("[name=" + name + "]").length) {
if (!/radio|checkbox/i.test($el.attr('type')) || $el.prop('checked')) {
obj[name] = obj[name] || [];
obj[name].push($el.toJSO());
}
} else {
obj[name] = $el.toJSO();
}
});
return obj;
};
I also made this one blog post to explain this more.
This converts everything in a form to JSON (even radio and check boxes) and all you'll have left to do is call
$.post('script.php',('form').toJSO(), ...);
I know there's plenty of ways to convert forms into JSON objects and sure .serialize()
and .serializeArray()
work great in most cases and are mostly intended to be used, but I think this whole idea of writing a form as an XML structure with meaningful names and converting it into a well-formed JSON object is worth the try, also the fact you can add same-name input tags without worrying is very useful if you need to retrive dynamically generated forms data.
I hope this helps someone!