149

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).

Deduplicator
  • 41,806
  • 6
  • 61
  • 104
seth
  • 2,331
  • 3
  • 18
  • 15
  • I guess what it boils down to is I'm looking for the most standards compliant way to access a form element using the name attribute... – seth Mar 12 '10 at 20:24
  • 5
    "having both is somewhat redundant, especially if the id isn't necessary for any css, and increases the likelihood of typos" -- ID is necessary for effective use of labels. Not just CSS. –  Mar 13 '10 at 09:38
  • 1
    Sometimes there are multiple forms on a webpage and id attributes can collide. – Calmarius Mar 10 '14 at 23:36

15 Answers15

104

Give your form an id only, and your input a name only:

<form id="myform">
  <input type="text" name="foo">

Then the most standards-compliant and least problematic way to access your input element is via:

document.getElementById("myform").elements["foo"]

using .elements["foo"] instead of just .foo is preferable because the latter might return a property of the form named "foo" rather than a HTML element!

Doin
  • 6,230
  • 3
  • 31
  • 31
  • I had no idea there were so many options! But I like this answer best, combined with using validateForm(this) to pass the form object. – John Henckel May 23 '14 at 16:52
  • Why is this preferred over onsubmit="myFunc(this); return false;"? – basickarl Aug 17 '16 at 12:52
  • 1
    @Karl... What are you trying to achieve? Aside from the fact that inlining JS into your HTML is rather inelegant (and often inefficient, since it creates a wrapper function around the code), the fact that you **always** return false means your form will **never** submit. So unless either the form isn't meant to be submitted (perhaps it's used entirely by JS code), or unless myFunc(this) submits it via AJAX (and you don't care about doing a regular submit as a fallback in case AJAX fails somehow), ...then you've made a mistake. – Doin Aug 18 '16 at 18:32
  • 1
    Normally, to submit only valid form data, you'd do: `myform.onsubmit = validateForm;` (where myform is a variable referencing the form element, and validateForm is the name of your validation function... but you can name it myFunc if you _really_, _really_ want to). The important point is that `validateForm()` should return **false** whenever the form is not valid, as well as indicating the problem field(s) to the user. It should return **true** when the form data validates correctly, which will allow the submit action to go ahead. – Doin Aug 18 '16 at 18:39
  • So...how do you associate all your form elements with their labels without an `id`? `aria-*`? – Jeromy French Dec 07 '16 at 20:19
  • @Jeromy, the easiest way to use labels is to enclose the form element in the label tag - then you don't need any explicit association between element and label. If/when that's not convenient, then yes, go ahead and give your form elements `id` attributes as well as `name` attributes. (Generally, making the `name` and `id` the same is a good rule-of-thumb when doing this, but it's not essential... and in particular `id`s should be unique in a document, while element names needn't be, either between different forms or even within the same form, so there are certainly counterexamples). – Doin Dec 09 '16 at 02:47
  • @Jeromy, just to clarify: `id`s on form elements are not the optimal answer *to the OP's question*, which is why I said not to use them. I'm not saying you should *never* use them! If you need to associate a label that isn't the element's parent, if you need to pick out a specific element for CSS styling, or if you need quick access to a particular element from javascript (as opposed to a general way to access form elements, which is what the question asked for), then you should go ahead give your form element an `id`! – Doin Dec 09 '16 at 02:54
  • 2
    There is another reason to avoid ids in form fields: in case you want multiple instances of the same form (in the same page). – koriander Jun 21 '17 at 20:59
  • @koriander Exactly. It's very difficult to ensure uniqueness in the entire document when using id's for field identifiers. Even if you aren't going to re-use the same form, the name you choose could easily clash with another form that a different developer (or yourself even after some time has passed) adds to the page. – crush Mar 06 '18 at 13:53
  • thanks! this way we can avoid multiple forms id attr collide. – roger Mar 18 '18 at 03:24
  • why not `document.getElementById("myform").elements.foo` ? – João Pimentel Ferreira Jul 19 '19 at 15:42
  • 1
    @João that works too, *provided* "foo" is valid as a javascript property name. (It might not be - HTML5 places almost no restrictions on the value of the `name` attribute, so e.g. you can have ``, which can't be referenced using javascript .propertyName notation). Explicit [] notation also allows names built from expressions, e.g. `myCheckBox = document.getElementById("myform").elements["CHK"+i]`. Plus, stylistically, I think [] is better- it makes it clear these aren't just properties of a javascript object. YMMV. – Doin Jul 19 '19 at 20:16
  • @Doin thank you, but consider that protocols such as standardJS or eslint will pop up a warning when accessing something like `.elements["foo"]` – João Pimentel Ferreira Jul 19 '19 at 21:05
  • @Doin btw, do you know if is completely safe to use `.elements["foo"]` if `foo` is merely an `id` of the form (form with no `name`s)? – João Pimentel Ferreira Jul 19 '19 at 21:16
  • @João Uh, what kind of warning? The `form.elements["foo"]` syntax is *certainly* correct and standard syntax. To your second comment, you misunderstand what `elements` is for. It is a *property* of a form, listing the controls *in* the form, by both their *name* attributes and by a numeric index (also). Look it up on MDN! Since it (a) lists controls *within* a form, and (b) lists by *name*, and **NOT** by *id* (**NOT** the same thing!), `form.elements["foo"]` will be `null` in your example where *foo* is a form id (unless it's *also* coincidentally the name of a control in *form*). – Doin Jul 20 '19 at 09:07
  • @Doin nope, check my example underneath and I read also MDN documentation before asking. It seems the property `elements` of the Object form also allows you to access only by `id`, that is, HTML elements with no `name` and merely `id`, will also have a corresponding property on the object `elements`. – João Pimentel Ferreira Jul 21 '19 at 11:52
  • @Doin regarding your first question, check it out https://eslint.org/docs/rules/dot-notation – João Pimentel Ferreira Jul 21 '19 at 11:55
  • @João, Oops, you're right! id's are listed as well as names. But only for form controls, ``,` – Doin Jul 21 '19 at 16:26
  • 1
    Regarding linting, bear in mind that linting is a style guide only, and a linting "error" doesn't mean your javascript is invalid or incorrect. In this particular case, though, what the linting rule is saying is "prefer dot notation when referencing javascript object properties". That's a good idea, and I recommend that in general. **BUT** while the linter doesn't realize this, `elements` isn't a normal JS object, and `elements.foo` or `elements["foo"]` is actually getting converted to elements.namedItem("foo"). i.e. you're calling a DOM-defined *function*, not referencing a JS property! – Doin Jul 21 '19 at 16:36
  • ...so for that reason, as well as also for the fact that element `name` and `id` attributes need not be valid as JS object names, I much prefer [] notation in this **very specific** case. But it's just a matter of style, and if you know that your name or id `foo` (for example) is valid as a JS identifier, then sure, you can go ahead and use `elements.foo` if you prefer to, or if you feel compelled to eliminate every last linting warning! – Doin Jul 21 '19 at 16:53
  • 1
    @João, sorry for misinterpreting earlier, but now I realize what you were *actually* asking when you asked "do you know if it is completely safe...", the answer to that question is "yes, it's completely safe" (at least according to the W3C standards... and in this case I'm also fairly confident that this has worked since IE6 days and even earlier). Where MDN doesn't give enough info to be 100% certain, you can always try looking at the w3.org or whatwg.org specs instead. These can be hard to interpret, as they really target browser implementors, but they're the definitive last word. – Doin Jul 21 '19 at 17:20
38

[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 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.

HoldOffHunger
  • 10,963
  • 6
  • 53
  • 100
Justin Johnson
  • 29,495
  • 7
  • 60
  • 86
  • 2
    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 Mar 12 '10 at 20:54
  • 1
    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 Mar 12 '10 at 20:56
  • 2
    @Justin, it's the name attribute that gets passed to the server. – Anurag Mar 13 '10 at 03:32
  • 2
    @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 Mar 13 '10 at 03:49
  • @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 Mar 13 '10 at 04:03
  • 1
    @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 Mar 13 '10 at 07:57
  • @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 Mar 13 '10 at 08:40
14

To access named elements placed in a form, it is a good practice to use the form object itself.

To access an arbitrary element in the DOM tree that may on occasion be found within a form, use getElementById and the element's id.

Michael
  • 5,910
  • 4
  • 52
  • 74
Sergey Ilinsky
  • 29,849
  • 9
  • 51
  • 56
  • 8
    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 Mar 12 '10 at 20:34
  • 2
    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 Mar 12 '10 at 21:21
  • I'm defining the style of my code...and as a preference I'm sticking to IDs....that way element access is consistent across the page. + the other reasons mentioned. –  Aug 09 '12 at 22:30
  • 1
    Why is it a good practice to access the form using getElementID? why would document.myForm not work? (I have a situation where its not working and I'm wondering why) – Spundun Aug 12 '13 at 22:42
  • Hey Spundun, you probably solved your issue months ago (or maybe you threw your hands up :) ), but in case you were wondering, it was probably due to your not supplying your form HTML element with a "name" attribute. – Sheldon R. Feb 28 '14 at 17:35
8

I much prefer a 5th method. That is
[5] Use the special JavaScript identifier this to pass the form or field object to the function from the event handler.

Specifically, for forms:

<form id="form1" name="form1" onsubmit="return validateForm(this)">

and

// The form validation function takes the form object as the input parameter
function validateForm(thisForm) {
  if (thisform.fullname.value !=...

Using this technique, the function never has to know
- the order in which forms are defined in the page,
- the form ID, nor
- the form name

Similarly, for fields:

<input type="text" name="maxWeight">
...
<input type="text" name="item1Weight" onchange="return checkWeight(this)">
<input type="text" name="item2Weight" onchange="return checkWeight(this)">

and

function checkWeight(theField) {
  if (theField.value > theField.form.maxWeight.value) {
    alert ("The weight value " + theField.value + " is larger than the limit");
    return false;
  }
return true;
}

In this case, the function never has to know the name or id of a particular weight field, though it does need to know the name of the weight limit field.

Robin Richmond
  • 128
  • 1
  • 5
  • Not sure what the underlying cause is, but I've had this approach return empty strings in some, but not all, circumstances. – Jacob Lee Jun 12 '15 at 20:57
8

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

[3] requires both an id and a name... having both is somewhat redundant

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?).

It is somewhat redundant, although less so when you have checkboxes/radio buttons, where several of them can share a name. Ultimately, id and name are for different purposes, even if both are often set to the same value.

Paul D. Waite
  • 89,393
  • 53
  • 186
  • 261
  • 5
    If you wrap an input in its label, you do not need an id or a for attribute. – kennebec Mar 13 '10 at 00:20
  • 3
    Very true, although that does limit what you can achieve in terms of look and feel. – Paul D. Waite Mar 13 '10 at 09:45
  • 2
    @kennebec—you should always use an id if you want the label to be associated with an element. Older versions of IE (< 8?) didn't associate elements inside a label with the label if there weren't matching *for* and *id* attributes. – RobG Aug 10 '12 at 01:54
  • In addition to what @kennebec wrote, using IDs creates JS globals and should be avoided. – mikemaccana Jan 06 '14 at 16:09
  • 1
    @mikemaccana: I have seen that cause issues before. I do think if your IDs are reasonably descriptive and your JavaScript is namespaced sensibly, it’s unlikely to cause issues though. – Paul D. Waite Jan 07 '14 at 00:53
6

This is a bit old but I want to add a thing I think is relevant.
(I meant to comment on one or 2 threads above but it seems I need reputation 50 and I have only 21 at the time I'm writing this. :) )
Just want to say that there are times when it's much better to access the elements of a form by name rather than by id. I'm not talking about the form itself. The form, OK, you can give it an id and then access it by it. But if you have a radio button in a form, it's much easier to use it as a single object (getting and setting its value) and you can only do this by name, as far as I know.

Example:

<form id="mainForm" name="mainForm">
    <input type="radio" name="R1" value="V1">choice 1<br/>
    <input type="radio" name="R1" value="V2">choice 2<br/>
    <input type="radio" name="R1" value="V3">choice 3
</form>

You can get/set the checked value of the radio button R1 as a whole by using
document.mainForm.R1.value
or
document.getElementById("mainForm").R1.value
So if you want to have a unitary style, you might want to always use this method, regardless of the type of form element. Me, I'm perfectly comfortable accessing radio buttons by name and text boxes by id.

VSim
  • 101
  • 2
  • 8
  • What works is `document.forms.mainForm.R1.value`, which is indeed a nice way to avoid using the ugly and tedious-to-type `document.getElementById()` – Kai Carver Apr 28 '20 at 09:42
2

Being old-fashioned I've always used the 'document.myform.myvar' syntax but I recently found it failed in Chrome (OK in Firefox and IE). It was an Ajax page (i.e. loaded into the innerHTML property of a div). Maybe Chrome didn't recognise the form as an element of the main document. I used getElementById (without referencing the form) instead and it worked OK.

1

Just to add to everything already said, you may access the inputs either with the name or id using preferably the elements property of the Object form, because without it you may get a property of the form named "foo" rather than an HTML element. And according to @Paul D. Waite it's perfectly ok to have both name and id.

var myForm = document.getElementById("myform")
console.log(myForm.foo.value) // hey
console.log(myForm.foo2.value) // hey
//preferable
console.log(myForm.elements.foo.value) // hey
console.log(myForm.elements.foo2.value) // hey
<form id="myform">
  <input type="text" name="foo" id="foo2" value="hey">
</form>

According to MDN on the HTMLFormElement.elements page

The HTMLFormElement property elements returns an HTMLFormControlsCollection listing all the form controls contained in the element. Independently, you can obtain just the number of form controls using the length property.

You can access a particular form control in the returned collection by using either an index or the element's name or id.

João Pimentel Ferreira
  • 9,166
  • 6
  • 52
  • 67
1

name field works well. It provides a reference to the elements.

parent.children - Will list all elements with a name field of the parent. parent.elements - Will list only form elements such as input-text, text-area, etc

var form = document.getElementById('form-1');
console.log(form.children.firstname)
console.log(form.elements.firstname)
console.log(form.elements.progressBar); // undefined
console.log(form.children.progressBar);
console.log(form.elements.submit); // undefined
<form id="form-1">
  <input type="text" name="firstname" />
  <input type="file" name="file" />
  <progress name="progressBar" value="20" min="0" max="100" />
  <textarea name="address"></textarea>
  <input type="submit" name="submit" />
</form>

Note: For .elements to work, the parent needs to be a <form> tag. Whereas, .children will work on any HTML-element - such as <div>, <span>, etc.

Good Luck...

Aakash
  • 14,077
  • 4
  • 77
  • 63
0

My answer will differ on the exact question. If I want to access a certain element specifically, then will I use document.getElementById(). An example is computing the full name of a person, because it is building on multiple fields, but it is a repeatable formula.

If I want to access the element as part of a functional structure (a form), then will I use:

var frm = document.getElementById('frm_name');
for(var i = 0; i < frm.elements.length;i++){
   ..frm.elements[i]..

This is how it also works from the perspective of the business. Changes within the loop go along with functional changes in the application and are therefor meaningful. I apply it mostly for user friendly validation and preventing network calls for checking wrong data. I repeat the validation server side (and add there some more to it), but if I can help the user client side, then is that beneficial to all.

For aggregation of data (like building a pie chart based on data in the form) I use configuration documents and custom made Javascript objects. Then is the exact meaning of the field important in relation to its context and do I use document.getElementById().

Loek Bergman
  • 2,092
  • 17
  • 18
0

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
  • 423
  • 2
  • 12
  • 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 Mar 12 '10 at 20:42
  • 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 Mar 15 '10 at 13:41
0

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.

Paul D. Waite
  • 89,393
  • 53
  • 186
  • 261
robert
  • 4,053
  • 1
  • 16
  • 20
  • @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 Mar 13 '10 at 04:01
  • 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).aspx In addition to Mozilla above, who else might not support it? – robert Mar 22 '10 at 17:53
0

I prefer This One

document.forms['idOfTheForm'].nameOfTheInputFiled.value;
  • 2
    Welcome to SO, we appreciate your input. Please edit your answer and explain the why and how. – B--rian Aug 27 '19 at 07:11
0

Because the case [2] document.myForm.foo is a dialect from Internet Exploere. So instead of it, I prefer document.forms.myForm.elements.foo or document.forms["myForm"].elements["foo"] .

0

To supplement the other answers, document.myForm.foo is the so-called DOM level 0, which is the way implemented by Netscape and thus is not really an open standard even though it is supported by most browsers.

  • 4
    Accessing forms and form controls by name, id and index is part of the DOM 2 HTML standard for [HTML collections](http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-75708506). – RobG Aug 10 '12 at 01:51