Jeez I don't know why I didn't think of this earlier.
I have many cases where the server will send a completed form in HTML format to an AJAX client - the client in those instances is simply a DIV waiting for data from the server. What I've never abstracted correctly is getting all the field information back up to the server - I've always just sort of slammed it together and not thought about making it one easy function and push.
So what I have here is a simple function that gets all INPUTs SELECTs and TEXTAREAs that are children of a passed node and JSON encodes them into a string. Inputs and selects may have an ID or not, it doesn't matter - if the target has an ID it will be used as the associative array name, otherwise I create names like input_0, input_1, select_0, textarea_0 and such. The "Base Node" in this function is any node on the DOM tree. For example, if you used the "BODY" node you'd send every single input/select/textarea on a page. If you want just a piece that is inside of a table, then pass the TABLE node to the function.
So assuming I have a div with the id 'formBaseNode' where all of my input fields are, I'd get all the input values like:
var uploadStr = encodeFields(document.getElementById('formBaseNode'));
... and uploadStr will be all JSONed up and ready to send up to the server.
The function here requires both getSelectValue and json_encode, which I've included in the source as well.
NOTE: The code here has been escaped to be sent as a stand-alone Javascript file - in other words, if you try to send this code back from a PHP script the escaping will be wrong and the javascript will not work. You can get both stand alone and PHP script versions of the json_encoder here:
http://www.perkiset.org/forum/javascript_ajax/json_encoder_for_javascript-t1094.0.html
Enjoy!
/perk
function encodeFields(baseNode)
{
var inputs = baseNode.getElementsByTagName('INPUT');
var sels = baseNode.getElementsByTagName('SELECT');
var texts = baseNode.getElementsByTagName('TEXTAREA');
var outArr = new Array();
var ptr = 0;
for (var i=0; i<inputs.length; i++)
{
var thisID = inputs[i].id;
if (!thisID) thisID = 'input_' + ptr;
outArr[thisID] = inputs[i].value;
ptr++;
}
var ptr = 0;
for (var i=0; i<sels.length; i++)
{
var thisID = sels[i].id;
if (!thisID) thisID = 'select_' + ptr;
outArr[thisID] = getSelectValue(sels[i])
ptr++;
}
var ptr = 0;
for (var i=0; i<texts.length; i++)
{
var thisID = texts[i].id;
if (!thisID) thisID = 'textarea_' + ptr;
outArr[thisID] = texts[i].value;
ptr++;
}
return json_encode(outArr);
}
function getSelectValue(selectID)
{
if (typeof(selectID) == 'string')
var target = document.getElementById(selectID);
else
target = selectID;
return target.options[target.selectedIndex].value;
}
function json_encode(inVal) { return _json_encode(inVal).join(''); }
function _json_encode(inVal, out)
{
out = out || new Array();
var undef; // undefined
switch (typeof inVal)
{
case 'object':
if (!inVal)
{
out.push('null');
} else {
if (inVal.constructor == Array)
{
// Need to make a decision... if theres any associative elements of the array
// then I will block the whole thing as an object {} otherwise, I'll block it
// as a normal array []
var testVal = inVal.length;
var compVal = 0;
for (var key in inVal) compVal++;
if (testVal != compVal)
{
// Associative
out.push('{');
i = 0;
for (var key in inVal)
{
if (i++ > 0) out.push(',\n');
out.push('"');
out.push(key);
out.push('":');
_json_encode(inVal[key], out);
}
out.push('}');
} else {
// Standard array...
out.push('[');
for (var i = 0; i < inVal.length; ++i)
{
if (i > 0) out.push(',\n');
_json_encode(inVal[i], out);
}
out.push(']');
}
} else if (typeof inVal.toString != 'undefined') {
out.push('{');
var first = true;
for (var i in inVal)
{
var curr = out.length; // Record position to allow undo when arg[i] is undefined.
if (!first) out.push(',\n');
_json_encode(i, out);
out.push(':');
_json_encode(inVal[i], out);
if (out[out.length - 1] == undef)
{
out.splice(curr, out.length - curr);
} else {
first = false;
}
}
out.push('}');
}
}
return out;
case 'unknown':
case 'undefined':
case 'function':
out.push(undef);
return out;
case 'string':
out.push('"');
out.push(inVal.replace(/(["\\])/g, '\$1').replace(/\r/g, '').replace(/\n/g, '\n'));
out.push('"');
return out;
default:
out.push(String(inVal));
return out;
}
}