The Cache: Technology Expert's Forum
 
*
Welcome, Guest. Please login or register. February 12, 2012, 08:44:31 AM

Login with username, password and session length


Pages: [1]
  Print  
Author Topic: Uploading Form Field Data Technique & Source  (Read 2375 times)
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 9792



View Profile
« on: September 08, 2008, 03:01:46 PM »

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

Code:
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;
}
}
Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
vsloathe
vim ftw!
Global Moderator
Lifer
*****
Offline Offline

Posts: 1669



View Profile
« Reply #1 on: September 08, 2008, 03:05:14 PM »

Nice man, and very useful.

I use a similar technique for scraping forms using PHP's DOM implementation.
Logged

hai
nutballs
Administrator
Lifer
*****
Online Online

Posts: 5604


Back in my day we had 9 planets


View Profile
« Reply #2 on: September 08, 2008, 03:35:52 PM »

so technically this reduces the amount of javascript junk on the client side. since technically you have broken the process down to:
insert HTML into node.
On Submit, send contents of submitted node to server.

thats it right?
Logged

I could eat a bowl of Alphabet Soup and shit a better argument than that.
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 9792



View Profile
« Reply #3 on: September 08, 2008, 03:53:31 PM »

Zactly - except that you're only sending the DATA contents back up to the server, not the entire contents of the node, which would include HTML and such - but I'm certain you know that.

In a totally normalized world, you could do a select * from a table where id=
  • , then create a form on the fly using the column names for both captions and ids, send the completed and ready-to-fill-in form out to an AJAX client, let the user update it, then JSON it all back up and you (the coder) would never know what fields were getting edited ie., you could change the DB and the client editor would instantly respond. Obviously, there's a little bit more complexity there if you want to make it look good, but that's essentially it.
Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 9792



View Profile
« Reply #4 on: September 16, 2008, 10:24:05 PM »

Update: I just ran across a situation that I'd not done before - I had radio buttons one of these types of forms. This might sound silly, but in the kind of forms that I use this thing for, I rarely have radios. So anyhoo, I was using it and radios did not "value" out right, so I updated the code here. Additionally, I had some other forms that I tried using it with where I had either an ID on an input or a NAME, sometimes both. So this little update uses either the id or the name for the output array, but biases towards the ID. Not a huge updated, but handy.

Code:
<?php

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=0i<inputs.lengthi++)
{
var thisID inputs[i].id;
if (!thisIDthisID inputs[i].name;
if (!thisIDthisID 'input_' ptr;

if (inputs[i].getAttribute('type') == 'radio')
{
if (inputs[i].checkedoutArr[thisID] = inputs[i].value;
} else {
outArr[thisID] = inputs[i].value;
}
ptr++;
}

var ptr 0;
for (var i=0i<sels.lengthi++)
{
var thisID sels[i].id;
if (!thisIDthisID sels[i].name;
if (!thisIDthisID 'select_' ptr;
outArr[thisID] = getSelectValue(sels[i])
ptr++;
}

var ptr 0;
for (var i=0i<texts.lengthi++)
{
var thisID texts[i].id;
if (!thisIDthisID texts[i].name;
if (!thisIDthisID 'textarea_' ptr;
outArr[thisID] = texts[i].value;
ptr++;
}

return json_encode(outArr);
}

?>

Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
nutballs
Administrator
Lifer
*****
Online Online

Posts: 5604


Back in my day we had 9 planets


View Profile
« Reply #5 on: September 17, 2008, 06:52:04 AM »

you probably want to deal with checkboxes as well. Im guessing those will have some kind of issue.
Logged

I could eat a bowl of Alphabet Soup and shit a better argument than that.
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 9792



View Profile
« Reply #6 on: September 17, 2008, 07:21:02 AM »

checkboxes already come across just fine ... the difference with radios is that you have several input nodes that only provide a single value (the one that was checked) - but now that you mention it, I'm not sure why checkboxes come across just fine LOL. I use checkboxes all the time. I'll have to play with that and see what I was thinking and how it works.
Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
nutballs
Administrator
Lifer
*****
Online Online

Posts: 5604


Back in my day we had 9 planets


View Profile
« Reply #7 on: September 17, 2008, 08:00:27 AM »

checkboxes always cause problems for me, because they are not sent via a normal post/get if none are selected. really annoying for form validation server side. but I guess since youare collecting the entire form on the client side, packaging it up and sending it, the checkboxes would work, since for the most part you have created your own POST method.
Logged

I could eat a bowl of Alphabet Soup and shit a better argument than that.
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 9792



View Profile
« Reply #8 on: September 17, 2008, 12:33:52 PM »

Indeed, CheckBoxes are a PIA. Youknow, given this little line of thinking, I'm going to update a titch just for these situations.

Don't change that dial!
Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
Pages: [1]
  Print  
 
Jump to:  

Perkiset's Place Home   Best of The Cache   phpMyIDE: MySQL Stored Procedures, Functions & Triggers
Politics @ Perkiset's   Pinkhat's Perspective   
cache
mart
coder
programmers
ajax
php
javascript
Powered by MySQL Powered by PHP Powered by SMF 1.1.2 | SMF © 2006-2007, Simple Machines LLC
Seo4Smf v0.2 © Webmaster's Talks


Valid XHTML 1.0! Valid CSS!