views:

277

answers:

5

As any seasoned JavaScript developer knows, there are many (too many) ways to do the same thing. For example, say you have a text field as follows:

<form name="myForm">  
    <input type="text" name="foo" id="foo" />

There are many way to access this in JavaScript:

[1]  document.forms[0].elements[0];
[2]  document.myForm.foo;
[3]  document.getElementById('foo');
[4]  document.getElementById('myForm').foo;
     ... and so on ...

Methods [1] and [3] are well documented in the Mozilla Gecko documentation, but neither are ideal. [1] is just too general to be useful and [3] requires both an id and a name (assuming you will be posting the data to a server side language). Ideally, it would be best to have only an id attribute or a name attribute (having both is somewhat redundant, especially if the id isn't necessary for any css, and increases the likelihood of typos, etc).

[2] seems to be the most intuitive and it seems to be widely used, but I haven't seen it referenced in the Gecko documentation and I'm worried about both forwards compatibility and cross browser compatiblity (and of course I want to be as standards compliant as possible).

So what's best practice here? Can anyone point to something in the DOM documentation or W3C specification that could resolve this?

Note I am specifically interested in a non-library solution (jQuery/Prototype).

+4  A: 

To access named elements placed in a form, it is a good practice to use form object itself. To access an arbitrary element in the DOM tree that may be by an occasion found within form, use id and getElementById

Sergey Ilinsky
What do you mean "use form object itself"? Once you have the form object, what method do you use to access a particular element?
seth
I mean I would recommend using N5 (document.getElementById('myForm').elements.foo) to access named items and N6 (document.getElementById('myForm').elements) to access the iteratable collection of elements
Sergey Ilinsky
A: 

Form 2 is ok, and form 3 is also recommended.
Redundancy between name and id is caused by the need to keep compatibility, on html 5 some elements (as img, form, iframe and such) will lose their "name" attribute, and it's recommended to use just their id to reference them from now on :)

wintermute
It seems input elements will never lose their name attribute due to the way it is used by server side languages. So the question remains, what's the standards compliant method if you only have the name attribute set?
seth
In a standards compliant development you wouldn't have just the name, for starters. If you really CAN'T have ID, then I'd suggest document.getElementByName() function.
wintermute
A: 

[1] document.forms[0].elements[0];

"No-omg-never!" comes to mind when I see this method of element access. The problem with this is that it assumes that the DOM is a normal data structure (e.g.: an array) wherein the element order is static, consistent or reliable in anyway. We know that 99.9999% of the time, that this is not the case. Reordering or input elements within the form, adding another form to the page before the form in question, or moving the the form in question are all cases where this code breaks. Short story: this is very fragile. As soon as you add or move something, it's going to break.

[2] document.myForm.foo;

I'm with Sergey ILinsky on this:

  • Access arbitrary elements by referring to their id attribute: document.getElementById("myform");
  • Access named form elements by name, relative to their parent form element: document.getElementById("myform").foo;

My main issue with this method is that the name attribute is useless when applied to a form. The name is not passed to the server as part of the POST/GET and doesn't work for hash style bookmarks.

[3] document.getElementById('foo');

In my opinion, this is the most preferable method. Direct access is the most concise and clear method.

[4] document.getElementById('myForm').foo;

In my opinion, this is acceptable, but more verbose than necessary. Method #3 is preferable.


I just so happened to be watch a video from Douglas Crockford and he weighed in on this very subject. The point of interest is at -12:00. To summarize:

  • Document collections (document.anchor, document.form, etc) are obsolete and irrelevant (method 1).
  • The name attribute is used to name things, not to access them. It is for naming things like windows, input fields, and anchor tags.
  • "ID is the thing that you should use to uniquely identify an element so that you can get access to it. They (name and ID) used to be interchangeable, but they aren't anymore."

So there you have it. Semantically, this makes the most sense.

Justin Johnson
So is this just a hack? document.getElementById("myform").foo;After studying the DOM quite a bit, I'm unclear as to why this even works. My guess is the form object is also an array of it's child elements indexed on the html name attribute...
seth
Also you mention "the name is not passed to the server as part of the POST/GET and doesn't work for hash style bookmarks". Isn't this precisely what IS passed to the server? When you are working with PHP, it's the name attribute that is your index in the $_POST global.
seth
@Justin, it's the name attribute that gets passed to the server.
Anurag
@seth The older DOM specs seem very vague about why `document.aForm.foo` works, but the HTML5 spec seems to clearly define the interface of an `HTMLFormElement` which has `caller getter any namedItem(in DOMString name);`. More at http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#the-form-element
Anurag
@Anurag this is great info, though brings me back to my initial question, what is best practice (and I realize there probably isn't one)... I'm just at a loss as to what to tell my JS students
seth
@both you guys: "...the name attribute is useless when applied to a form..." I'm not talking about the name attribute of an `input` or `select`, I'm talking about the name attribute of a `form`. The name attribute of a `form` *does not* get passed to the server.
Justin Johnson
@Justin.. I missed that, you are right - the form's name attribute is not sent to the server. @seth I think it depends on the kind of students you are teaching. If they're college students studying Computer Science, for example, you can tell them about all 4 ways, and why the first way is terrible as Justin pointed out. Otherwise finding by ID is pretty standard and so is named access for forms and its elements.
Anurag
A: 

Hi there, check out this page: https://developer.mozilla.org/En/DOM/Document.getElementsByName

document.getElementsByName('foo')[0]; // returns you element.

It has to be 'elements' and must return an array because more than one element could have the same name.

-Rob

robert
As far as I know getElementsByName isn't cross browser...
seth
@robert, I'm now thinking this might be a good solution, though this straight out of the docs made me nervous:"This method might be questionable for use given the above changes between document types and the current non-standard behavior for this method in XHTML. "
seth
Hi there. Which documentation suggested against this? I think if you're using xhtml in all the DOM environments you're working in, then you should be OK. Also, which browsers don't support this? Here is the docs for IE: http://msdn.microsoft.com/en-us/library/ms536438(VS.85).aspxIn addition to Mozilla above, who else might not support it?
robert
+2  A: 

It’s not really answering your question, but just on this part:

[3] requires both an id and a name

you’ll most likely need to have an id attribute on each form field anyway, so that you can associate its <label> element with it, like this:

<label for="foo">Foo:</label>
<input type="text" name="foo" id="foo" />

This is required for accessibility (i.e. if you don’t associate form labels and controls, why do you hate blind people so much?)

Paul D. Waite
If you wrap an input in its label,you do not need an id or a for attribute.<label>Foo:<input type="text" name="foo" </label>
kennebec
Very true, although that does limit what you can achieve in terms of look and feel.
Paul D. Waite