Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Javascript > form serialization (Code Worth Recommending Project)

Reply
Thread Tools

form serialization (Code Worth Recommending Project)

 
 
Peter Michaux
Guest
Posts: n/a
 
      11-07-2007
If all goes well, this is part one of what will hopefully result in a
body of code the group can recommend as a resource for JavaScript
programmers and library writers. At the very least it's something
constructive we can bicker over rather than just ridiculing the
popular JavaScript libraries.

I'm not yet sure how this code will be aggregated but it seems that
Jim Ley will be making some changes on the jibbering server soon and
perhaps this code will end up in a wiki or svn repository on the
jibbering site or elsewhere.

This first installment is about form serialization. This is a common
task these days and something not covered in the group's FAQ notes.
Below is an example of form serialization that works with forms with
text-like inputs (eg text, hidden, textarea, etc). This follows
Richard Cornford's idea of having multiple implementations of a single
interface where each implementation is for a specific circumstance.
Other implementations for forms with select, radio and checkbox inputs
can be written (and I have written some.) Perhaps first it would be a
good idea to criticize my implementation and documentation below for
the stated circumstance much like the daily FAQ posts are heavily
scrutinized.

//
----------------------------------------------------------------------------

/**
@object serializeForm<function>

@param f<form> The form element to be serialized.

@returns <string> The serialized form data in "foo=bar&asdf=1234"
format

serializeForm will serialize data contained in forms with text-
like
inputs (eg. text, password, hidden, textarea.) The returned string
is suitable for a URL query string or POST request body. Test that
this function is defined before calling it. This function has
no side effects.

Features Not Tested
(ECMAScript v2, DOM 1 and earlier features are assumed to reduce
code size)
JavaScript 1.0
form.elements
form.elements.length
input.name
input.value
ECMAScript v1
array.join
DOM Level 1
input.disabled
*/

// ECMAScript v3 feature tests
if (Array.prototype.push && encodeURIComponent) {

function serializeForm(f) {
var i, // elements loop index
l, // elements loop length
e, // element
es = f.elements,
c = []; // the serialization data parts

for (i=0, l=es.length; i<l; i++) {
e = es[i];
if (!e.disabled) {
c.push(encodeURIComponent(e.name) + "=" +
encodeURIComponent(e.value));
}
}
return c.join('&');
}

}

 
Reply With Quote
 
 
 
 
RobG
Guest
Posts: n/a
 
      11-07-2007
On Nov 7, 3:42 pm, Peter Michaux <(E-Mail Removed)> wrote:
> If all goes well, this is part one of what will hopefully result in a
> body of code the group can recommend as a resource for JavaScript
> programmers and library writers. At the very least it's something
> constructive we can bicker over rather than just ridiculing the
> popular JavaScript libraries.
>
> I'm not yet sure how this code will be aggregated but it seems that
> Jim Ley will be making some changes on the jibbering server soon and
> perhaps this code will end up in a wiki or svn repository on the
> jibbering site or elsewhere.
>
> This first installment is about form serialization. This is a common
> task these days and something not covered in the group's FAQ notes.
> Below is an example of form serialization that works with forms with
> text-like inputs (eg text, hidden, textarea, etc). This follows
> Richard Cornford's idea of having multiple implementations of a single
> interface where each implementation is for a specific circumstance.
> Other implementations for forms with select, radio and checkbox inputs
> can be written (and I have written some.) Perhaps first it would be a
> good idea to criticize my implementation and documentation below for
> the stated circumstance much like the daily FAQ posts are heavily
> scrutinized.
>
> //
> ----------------------------------------------------------------------------
>
> /**
> @object serializeForm<function>
>
> @param f<form> The form element to be serialized.
>
> @returns <string> The serialized form data in "foo=bar&asdf=1234"
> format
>
> serializeForm will serialize data contained in forms with text-
> like
> inputs (eg. text, password, hidden, textarea.) The returned string
> is suitable for a URL query string or POST request body. Test that
> this function is defined before calling it. This function has
> no side effects.
>
> Features Not Tested
> (ECMAScript v2, DOM 1 and earlier features are assumed to reduce
> code size)
> JavaScript 1.0
> form.elements
> form.elements.length
> input.name
> input.value
> ECMAScript v1
> array.join
> DOM Level 1
> input.disabled
> */
>
> // ECMAScript v3 feature tests
> if (Array.prototype.push && encodeURIComponent) {
>
> function serializeForm(f) {
> var i, // elements loop index
> l, // elements loop length
> e, // element
> es = f.elements,
> c = []; // the serialization data parts
>
> for (i=0, l=es.length; i<l; i++) {
> e = es[i];
> if (!e.disabled) {
> c.push(encodeURIComponent(e.name) + "=" +
> encodeURIComponent(e.value));
> }
> }
> return c.join('&');
> }
> }


The above function seems a little simplistic. It should exclude form
controls that don't have a name, it should also deal with radio
buttons, selects, checkboxes, etc.

You might want to check with Matt Kruse's Ajax Toolbox which has a
form serialisation function:

<URL: http://www.ajaxtoolbox.com/request/d...#serializeForm
>



There is also IE's problem with reporting the value of an option
element (the text value should be reported if there is no value
attribute but IE doesn't).

<URL:
http://groups.google.com.au/group/co...18177bf1658a30
>


and

<URL: http://groups.google.com/group/comp....b462f76a?tvc=1
>




--
Rob

 
Reply With Quote
 
 
 
 
Peter Michaux
Guest
Posts: n/a
 
      11-07-2007
On 6 nov, 23:21, RobG <(E-Mail Removed)> wrote:
> On Nov 7, 3:42 pm, Peter Michaux <(E-Mail Removed)> wrote:
>
>
>
> > If all goes well, this is part one of what will hopefully result in a
> > body of code the group can recommend as a resource for JavaScript
> > programmers and library writers. At the very least it's something
> > constructive we can bicker over rather than just ridiculing the
> > popular JavaScript libraries.

>
> > I'm not yet sure how this code will be aggregated but it seems that
> > Jim Ley will be making some changes on the jibbering server soon and
> > perhaps this code will end up in a wiki or svn repository on the
> > jibbering site or elsewhere.

>
> > This first installment is about form serialization. This is a common
> > task these days and something not covered in the group's FAQ notes.
> > Below is an example of form serialization that works with forms with
> > text-like inputs (eg text, hidden, textarea, etc). This follows
> > Richard Cornford's idea of having multiple implementations of a single
> > interface where each implementation is for a specific circumstance.
> > Other implementations for forms with select, radio and checkbox inputs
> > can be written (and I have written some.) Perhaps first it would be a
> > good idea to criticize my implementation and documentation below for
> > the stated circumstance much like the daily FAQ posts are heavily
> > scrutinized.

>
> > //
> > ----------------------------------------------------------------------------

>
> > /**
> > @object serializeForm<function>

>
> > @param f<form> The form element to be serialized.

>
> > @returns <string> The serialized form data in "foo=bar&asdf=1234"
> > format

>
> > serializeForm will serialize data contained in forms with text-
> > like
> > inputs (eg. text, password, hidden, textarea.) The returned string
> > is suitable for a URL query string or POST request body. Test that
> > this function is defined before calling it. This function has
> > no side effects.

>
> > Features Not Tested
> > (ECMAScript v2, DOM 1 and earlier features are assumed to reduce
> > code size)
> > JavaScript 1.0
> > form.elements
> > form.elements.length
> > input.name
> > input.value
> > ECMAScript v1
> > array.join
> > DOM Level 1
> > input.disabled
> > */

>
> > // ECMAScript v3 feature tests
> > if (Array.prototype.push && encodeURIComponent) {

>
> > function serializeForm(f) {
> > var i, // elements loop index
> > l, // elements loop length
> > e, // element
> > es = f.elements,
> > c = []; // the serialization data parts

>
> > for (i=0, l=es.length; i<l; i++) {
> > e = es[i];
> > if (!e.disabled) {
> > c.push(encodeURIComponent(e.name) + "=" +
> > encodeURIComponent(e.value));
> > }
> > }
> > return c.join('&');
> > }
> > }

>
> The above function seems a little simplistic. It should exclude form
> controls that don't have a name,


Yes it should. I will add this.


> it should also deal with radio
> buttons, selects, checkboxes, etc.


I have a version that does this to post later. It is bigger and wanted
to post something smaller to look at format of how one of the multiple
implementations might be presented. Each is simply an implementation
for a different circumstance but with the same interface.

Thanks,
Peter

 
Reply With Quote
 
Matt Kruse
Guest
Posts: n/a
 
      11-07-2007
On Nov 7, 6:18 am, Peter Michaux <(E-Mail Removed)> wrote:
> I have a version that does this to post later. It is bigger and wanted
> to post something smaller to look at format of how one of the multiple
> implementations might be presented. Each is simply an implementation
> for a different circumstance but with the same interface.


IMO, this example is taking that philosophy a bit too far. The extra
code required to handle all input types is minimal. Why would someone
want a stripped-down version that only handles a very limited case,
when they could have a fully reusable version that could be used in
every case? This problem is very "solvable" in that a single general-
purpose solution can be created. For different problems, that that's
not so true and the "many implementation" approach makes more sense.

In any case, my stab at it was posted by Rob. It does need to be
improved to handle the special select case in IE and maybe there are
some more quirks that exist that I didn't handle. You could surely
take the serialization code from a few different libs and combine them
into a single solution.

Matt Kruse



 
Reply With Quote
 
Martin Honnen
Guest
Posts: n/a
 
      11-07-2007
Peter Michaux wrote:

> // ECMAScript v3 feature tests
> if (Array.prototype.push && encodeURIComponent) {


Shouldn't that check be
if (Array.prototype.push && typeof encodeURIComponent != 'undefined')
? If you simply use the identifier encodeURIComponent then your code
throws an error in implementations not implementing encodeURIComponent.

> function serializeForm(f) {


A function declaration inside of the if block? That is not even allowed
syntax according to ECMAScript edition 3 as you can only put a statement
in the if block but function declarations are not statements. And
different implementations handle that case differently as it is not
specified, I think Mozilla's Spidermonkey indeed processes the function
declaration conditionally but with Microsoft's JScript the function
declaration is processed unconditionally.

--

Martin Honnen
http://JavaScript.FAQTs.com/
 
Reply With Quote
 
Peter Michaux
Guest
Posts: n/a
 
      11-07-2007
On Nov 7, 7:46 am, Matt Kruse <(E-Mail Removed)> wrote:
> On Nov 7, 6:18 am, Peter Michaux <(E-Mail Removed)> wrote:
>
> > I have a version that does this to post later. It is bigger and wanted
> > to post something smaller to look at format of how one of the multiple
> > implementations might be presented. Each is simply an implementation
> > for a different circumstance but with the same interface.

>
> IMO, this example is taking that philosophy a bit too far. The extra
> code required to handle all input types is minimal. Why would someone
> want a stripped-down version that only handles a very limited case,
> when they could have a fully reusable version that could be used in
> every case? This problem is very "solvable" in that a single general-
> purpose solution can be created. For different problems, that that's
> not so true and the "many implementation" approach makes more sense.


I agree this problem is quite solvable in general and is why I chose
it first. It is a chance to see how code could be aggregated with a
philosophy that is inclusive to encourage participation. Acknowledging
multiple implementations where people have different priorities
(download size verses generality is a legitimate argument) will make
the code base more reusable both educationally and by various people.
By having an inclusive approach established, when the trickier
problems are presented, I think we will have more input to tackle
them.


> In any case, my stab at it was posted by Rob. It does need to be
> improved to handle the special select case in IE and maybe there are
> some more quirks that exist that I didn't handle. You could surely
> take the serialization code from a few different libs and combine them
> into a single solution.


The option wrinkle is not as simple as it seems. In fact, I think
there is no general JavaScript-only solution to that problem and the
multiple implementations approach is the only way. I didn't know that
until I started making examples for this. Various solutions require
either supported browser restrictions or HTML authoring restrictions.
I will post what I have when this simpler version is sorted.

Thanks,
Peter

 
Reply With Quote
 
Peter Michaux
Guest
Posts: n/a
 
      11-07-2007
On Nov 7, 8:31 am, Martin Honnen <(E-Mail Removed)> wrote:
> Peter Michaux wrote:
> > // ECMAScript v3 feature tests
> > if (Array.prototype.push && encodeURIComponent) {

>
> Shouldn't that check be
> if (Array.prototype.push && typeof encodeURIComponent != 'undefined')
> ? If you simply use the identifier encodeURIComponent then your code
> throws an error in implementations not implementing encodeURIComponent.


Indeed. Silly mistake that I've encountered before.


> > function serializeForm(f) {

>
> A function declaration inside of the if block? That is not even allowed
> syntax according to ECMAScript edition 3 as you can only put a statement
> in the if block but function declarations are not statements. And
> different implementations handle that case differently as it is not
> specified, I think Mozilla's Spidermonkey indeed processes the function
> declaration conditionally but with Microsoft's JScript the function
> declaration is processed unconditionally.


Thanks. I didn't know this. It seems that JavaScript(TM) does allow a
FunctionDeclaration inside a Block but the ECMAScript v3 specification
does not. It is quite an ordeal to verify that an IfStatement can
contain a FunctionExpression through this series of productions:
IfStatement, Block, StatementList, Statement, VariableStatement,
VariableDeclarationList, VariableDeclaration, Initialiser,
AssignmentExpression, ConditionalExpression, LogicalORExpression,
LogicalANDExpression, BitwiseORExpression, BitwiseXORExpression,
BitwiseANDExpression, EqualityExpression, RelationalExpression,
ShiftExpression, AdditiveExpression, MultiplicativeExpression,
UnaryExpression, PostfixExpression, LeftHandSideExpression,
NewExpression, MemberExpression, FunctionExpression.


Revised code...

if (Array.prototype.push && typeof encodeURIComponent != 'undefined')
{

var serializeForm = function(f) {
var i, // elements loop index
l, // elements loop length
e, // element
es = f.elements,
c = []; // the serialization data parts

for (i=0, l=es.length; i<l; i++) {
e = es[i];
if (e.name && !e.disabled) {
c.push(encodeURIComponent(e.name) + "=" +
encodeURIComponent(e.value));
}
}
return c.join('&');
}

}


Thanks again,
Peter

 
Reply With Quote
 
Matt Kruse
Guest
Posts: n/a
 
      11-07-2007
On Nov 7, 11:31 am, Peter Michaux <(E-Mail Removed)> wrote:
> The option wrinkle is not as simple as it seems. In fact, I think
> there is no general JavaScript-only solution to that problem and the
> multiple implementations approach is the only way.


This is my solution. I haven't encountered a situation where it fails
(yet). If you can find one, I'd like to try to improve the code to
handle it:

function selectValue(sel) {
if (sel.options && sel.options.length) {
var selected = [];
for (var i=0; i<sel.options.length; i++) {
var opt = sel.options[i];
if (sel.options[i].selected) {
var val = null;
// This mess is here because an option can have no value
attribute, in which case the text property is used.
// But IE messes up and gives a blank string as .value, even when
value doesn't exist. Yuck.
if (opt.value!="") { val = opt.value; }
else if (!'value' in opt) { val = opt.text; }
else if (opt.outerHTML && opt.outerHTML.test(/<[^>]+value\s*=/i))
{ val = opt.value; }
else { val = opt.text; }
if (sel.type=="select-one") {
return val;
}
selected.push(val);
}
}
return selected;
}
}

Forgive me if it errors out, I actually slightly modified my code
before posting because it was part of a bigger method. But the logic
at least should be there.

Matt Kruse

 
Reply With Quote
 
Peter Michaux
Guest
Posts: n/a
 
      11-07-2007
On Nov 6, 11:21 pm, RobG <(E-Mail Removed)> wrote:
>
> There is also IE's problem with reporting the value of an option
> element (the text value should be reported if there is no value
> attribute but IE doesn't).
>
> <URL:http://groups.google.com.au/group/comp.lang.javascript/browse_frm/thread/a32139cf2fe20f60>
>
> and
>
> <URL:http://groups.google.com/group/comp.lang.javascript/browse_frm/thread/3b0ff7ccb462f76a>


Two getOptionValue functions were proposed in those threads. Neither
is bullet proof.

For both versions, if the value attribute is dynamically set to the
empty string, then Firefox will report the option's text property as
the option's value. An HTML page is appended below if anyone would
like to verify this problem with the two versions.

Matt's version will also be tricked if the option element has another
attribute which has a value containing the string fragment "value=" as
part of it's value. Elegie's version collapses the attribute values to
avoid this problem.

Peter



<html>
<head>
<title>getOptionValue</title>

// Matt Kruse
// <URL: http://groups.google.com/group/comp.lang.javascript/msg/3f5de3dcacef20d2>
String.prototype.test = function(regex) {
return regex.test(this);
}
function getOptionValue(opt) {
if (opt.value!="") {
return opt.value;
}
if (!'value' in opt) {
return opt.text;
}
if (opt.outerHTML && opt.outerHTML.test(/<[^>]+value\s*=/i)) {
return opt.value;
}
return opt.text;
}


// Elegie
// <URL: http://groups.google.com/group/comp.lang.javascript/msg/a5029b734629d5c5>
function getOptionValue(opt) {
var v = opt.value,
t = opt.text;

return (v || attributeExists(opt, "value")) ? v : t;

function attributeExists(obj, attrName) {
var oHtml = obj.outerHTML;
alert(oHtml)
var found = false;

if (oHtml)
found = /value\s*=/i.test(collapseQuotedValues(oHtml));

return found;

function collapseQuotedValues(txt){
var sQuote = txt.indexOf("'");
var dQuote = txt.indexOf("\"");
var q = "";

if (sQuote==-1 && dQuote!=-1) {
q ="\"";
} else if (sQuote!=-1 && dQuote==-1) {
q ="'"
} else if (sQuote!=-1 && dQuote!=-1) {
if (sQuote<dQuote) q = "'";
if (dQuote<sQuote) q = "\"";
}

if (q) txt = arguments.callee(
txt.replace(new RegExp(q+"[^"+q
+"]*"+q),"_")
);

return txt;
} // collapseQuotedValues

} // attributeExists

} // getOptionValue

</script>

<script type="text/javascript">

window.onload = function() {
var o = document.forms.foo.elements.bar.options[0];
o.value = '';
alert(getOptionValue(o)); // "hello" but should be empty
string
};

</script>

</head>
<body>

<form action="#" name="foo" method="get" accept-charset="utf-8">
<p>
<select name="bar">
<option>hello</option>
</select>
</p>
</form>

</body>
</html>

 
Reply With Quote
 
Peter Michaux
Guest
Posts: n/a
 
      11-07-2007
On Nov 6, 11:21 pm, RobG <(E-Mail Removed)> wrote:
>
> There is also IE's problem with reporting the value of an option
> element (the text value should be reported if there is no value
> attribute but IE doesn't).



This getOptionValue function is inspired by the form serialization
function in YUI's connection.js file.

function getOptionValue(o) {
return ((o.hasAttribute && o.hasAttribute('value')) ||
(o.attributes.value && o.attributes.value.specified)) ?
o.value : o.text;
}


The o.hasAttribute() function works in FF2 and S2 but not IE6. The
o.attributes.value.specified works in FF2 and IE6 but not S2. So both
checks are needed but what if neither works for a particular browser?
This situation exists in some older browsers and they will report
o.text when perhaps they should be reporting o.value.

One thing I don't understand is the direct access to the
o.attributes.value property. It seems to me that the spec says for a
NamedNodeMap it would instead need to be
o.attributes.getNamedItem('value'). Does anyone know about the
legality of the direct access use?

---------

The only "cross browser" solution I can think of is just develop so
this never matters. If the option element's value attribute is always
included in the HTML then we can write just the following which works
back to IE4/NN4.

function getOptionValue(o) {
return o.value;
}

The only argument against always including the value attribute is
space. For example, a list of countries is long and omitting the value
attribute would save quite a bit of space. On a page where countries
are used and the value attributes are omitted for just that select
element, we could write something like this.

function getOptionValue(o) {
return o.parentNode && o.parentNode.name == 'country' ? o.text :
o.value;
}

If we know that on the page there are some options that don't have a
value attribute specified but should never have an empty string as the
value, then we can write

function getOptionValue(o) {
return o.value || o.text;
}

Right now, it doesn't seem to me that there is a single bulletproof,
non-sniffing solution to getting the value of an option element when
the page can contain any combination of options and value attributes
and any browser may be used. With the multiple implementations we can
always choose one that works for a particular page or site, given the
rules by which the HTML authors are playing.

---------

Some links and notes I collected when looking into the YUI function...

Node interface
<URL: http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-core.html#ID-1780488922>
<URL: http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1950641247>

The Node interface specifies an "attributes" property which is a
NamedNodeMap.

HTMLOptionElement interface
<URL: http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-70901257>

The HTMLOptionElement interface extends the HTMLElement interface
which extends the Element interface which extends the Node interface.

The HTMLOptionElement interface specifies a read-write "value"
property. The initial value of the "value" property is set by the
value attribute in the HTML. If that attribute is not present then the
text of the element is used.

The HTMLOptionElement interface specifies a read-only "text" property.

Attr interface
<URL: http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-637646024>

The Attr interface specifies a read-only boolean "specified".

MS attributes collection
<URL: http://msdn2.microsoft.com/en-us/library/ms537438.aspx>

MS getNamedItem function (IE6+?)
<URL: http://msdn2.microsoft.com/en-us/library/ms536441.aspx>

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Various DOM-related wrappers (Code Worth Recommending Project) David Mark Javascript 152 12-16-2007 03:04 PM
status and plan (Code Worth Recommending Project) Peter Michaux Javascript 0 12-13-2007 03:11 AM
isFunction (Code Worth Recommending Project) David Mark Javascript 25 12-12-2007 01:56 AM
url encoding string (Code Worth Recommending Project) Peter Michaux Javascript 16 11-26-2007 07:44 PM



Advertisments