View Full Version : iterating through form elements... a newer way?

03-31-2003, 12:40 AM
Is this still the cool/kosher/best way to iterate through form elements?

(for example, below... checking all checkboxes in a form)

for ( i = 0; i < document.myForm.elements.length; i++ )
if (document.myForm.elements[i].type == 'checkbox' )
document.myForm.elements[i].checked = true;

Just wondering if there's some new technique I'm not aware of...

03-31-2003, 12:48 AM
I like a while loop:

var el, i = 0, oForm = document.myForm;
while (el = oForm.elements[i++]) if (el.type == 'checkbox') el.checked = true;

Easier if you simply pass the Form object: <form......onsubmit="whatever(this)">

03-31-2003, 10:32 AM
Haven't tested this, but I think you can do it through for...in:

var e=oForm.elements,i;
for(i in e)

03-31-2003, 10:58 PM
While loops are good and the faster between the two, but if you prefer for loops, this is your best bet

var e = document.myform.elements;
for ( var elem, i = 0; ( elem = e[i] ); i++ )
if ( elem.type == 'checkbox' )
elem.checked = true;
}Really alot like a while loop in a for loop's clothing ;)

04-01-2003, 12:04 AM
You must make a distinction here - a for loop is as little connected to a for...in loop as a while loop is. for is overloaded, and for...in is really another kind of beast. In fact, the for and while loops are both closer to eachother than to the for...in loop.

Evidently from actually testing that, you only get the enumerable members (length, item and namedItem) instead of the names of the children to iterate over, though. Thus, my nice little idea fell.

04-01-2003, 12:49 AM
Form element objects are stored in the ordered 'portion' of the Form.elements[] array, not the hashtable portion. Why would you even want to iterate through dozens of properties looking for pointer data (names) referencing the objects, when you know where they are, and that every one has a .type property to be read? Not sure what loop structure has to do with this..

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<script type="text/javascript" language="javascript">

function iterator1(oForm) {
var x = open('','','width=300,left=200,top=50,scrollbars,status=0');
var e = oForm.elements;
for(var i in e) x.document.write(i + ' : ' + e[i] + '\n');

function iterator2(oForm) {
var el, i = 0;
while (el = oForm.elements[i++]) if (el.type == 'checkbox') el.checked = true;

<input name="box1" type="checkbox"><br />
<input name="box2" type="checkbox"><br />
<input name="box3" type="checkbox"><br />
<input name="box4" type="checkbox"><br />
<input name="box5" type="checkbox"><br /><br />
<input type="button" value="check 1" onclick="iterator1(this.form)">
<input type="button" value="check 2" onclick="iterator2(this.form)">

04-01-2003, 12:50 AM
I tried three tests (see code below), iterating through the form.elements array.

In the first loop, output is over 100 attributes of the element (language, scrollHeight, isTextEdit, etc.), including, at the very end, the values 0, 1, 2 (indices into the elements[] array).

In the second loop, I test only for these three indices, then print the "type" attribute, which is "text" for each of my three form elements (you can also print out "value" to show that it's definitely the form elements we're accessing here).

In the third loop, I assumed (from the previous loop) that I could test for blah.type == 'text', but, for some reason, it doesn't work. Curious.

Anyway, because of the sheer volume (around 135) of attributes that you'd have to cycle through to get to the data you want, looks like it's best to avoid for..in to cycle through form.elements[].

For..in works great for a "regular" array, though, like [ 'one', 'two', 'three' ].

Thanks for all the comments.


<form name="_form">
&nbsp;&nbsp;&nbsp;&nbsp;<input type=text value='one'>
&nbsp;&nbsp;&nbsp;&nbsp;<input type=text value='two'>
&nbsp;&nbsp;&nbsp;&nbsp;<input type=text value='three'>
&nbsp;&nbsp;&nbsp;&nbsp;_a = document._form.elements;
&nbsp;&nbsp;&nbsp;&nbsp;for ( _i in _a )
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.write( _i, ': ', _a[ _i ], '<br>' );
&nbsp;&nbsp;&nbsp;&nbsp;document.write( '<p>' );

&nbsp;&nbsp;&nbsp;&nbsp;for ( _i in _a )
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ( _i == '0' || _i == '1' || _i == '2' )
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.write( _i, ': ', _a[ _i ].type, ': ', _a[ _i ], '<br>' );
&nbsp;&nbsp;&nbsp;&nbsp;document.write( '<p>' );

&nbsp;&nbsp;&nbsp;&nbsp;for ( _i in _a )
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ( _a[ _i ].type == 'text' )
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.write( _i, ': ', _a[ _i ], '<br>' );

04-01-2003, 01:03 AM
You should really only use for...in for objects, becuase that's the ONLY way to seqeuntially loop through the properties. Of course, any prototyped properties or methods will be caught by a for...in loop.

Regular arrays are based on indexes, a looping implementation that includes an index incrementation only makes sense.

Oh, and not ALL form elements have a type (SELECTs, TEXTAREAs)

if ( elem.nodeName == 'INPUT' && elem.type == 'checkbox' )

would be more appropriate :D

04-01-2003, 01:25 AM
Re: beetle's previous comments... is there some performance (or other) reason why I shouldn't do this?

var _a = [ 1, 2, 3 ];
for ( var _i in _a )
document.write( _a[ _i ] );
Code looks nice. No need for an explicit counter. Any downside? (I guess it's slower because it's using strings...)

04-01-2003, 01:27 AM
Oh, and not ALL form elements have a type (SELECTs, TEXTAREAs)http://www.cs.huji.ac.il/~ra9apz/javascript/select.html

04-01-2003, 01:44 AM

Hehe, thanks cheesebagpipe, I didn't realize that. :o

I swear, some days I open my mouth just to change feet. :rolleyes:

04-01-2003, 02:16 AM
Nice little problem this has turned in to:

for...in works perfectly over arrays, as it gets all enumerable properties and only keyed members are enumerable (of which indiced members are a subset). I'll soon have benchmarks for comparison to while, for, do...while. (There are no keyed members in an array unless you explicitly add them, but if you do they will be iterated over. This includes enumerable prototype properties.)

for...in also works perfectly over objects, but here there's no alternative. You get all the enumerable properties, which means all the keyed properties.

for...in doesn't work very well over collections, however. Collections have a few keyed properties, and they have a few indiced, but the indices aren't really keys (the object is overloaded as a getter for object.item(), in fact, and is not an array) and thus aren't in the iteration. All this because XML objects have three types of members while JSObjects only have one.

04-01-2003, 02:27 AM
Nice summary... looking forward to the benchmarks.

04-01-2003, 02:38 AM
You can use my StopWatch class (http://www.peterbailey.net/dev/jsclasses/) if you're gonna do timed tests :D

04-01-2003, 04:36 AM
Quick benchmark (http://liorean.web-graphics.com/scripts/benchmarks/loop.html)

Interesting facts:
ie op7 moz moz(strict)
0 110 431 110 110
1 120 431 110 13029
2 160 380 110 12678
3 141 341 100 100
4 180 2123 1192 1272

0. l=arr.length;for(i=0;l>i;i++)r+=arr[i];
1. for(i=0;(e=arr[i]);i++)r+=e;
2. i=0;while((e=arr[i++]))r+=e;
3. i=arr.length;do r+=arr[--i];while(i);
4. for(i in arr)r+=arr[i];

Moz with strict warnings is seriously harmed by assignment of undefined, because both of the UI interaction that follows, and the hooks to the debugger.