Práctica recomendada: ¿Acceder a elementos de formulario por ID HTML o atributo de nombre?

136

Como cualquier desarrollador experimentado de JavaScript sabe, hay muchas (demasiadas) formas de hacer lo mismo. Por ejemplo, supongamos que tiene un campo de texto de la siguiente manera:

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

Hay muchas formas de acceder a esto en JavaScript:

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

Los métodos [1] y [3] están bien documentados en la documentación de Mozilla Gecko, pero ninguno es ideal. [1] es demasiado general para ser útil y [3] requiere una identificación y un nombre (suponiendo que publicará los datos en un idioma del lado del servidor). Idealmente, sería mejor tener solo un atributo de identificación o un atributo de nombre (tener ambos es algo redundante, especialmente si la identificación no es necesaria para ningún CSS, y aumenta la probabilidad de errores tipográficos, etc.).

[2] parece ser el más intuitivo y parece ser ampliamente utilizado, pero no lo he visto mencionado en la documentación de Gecko y estoy preocupado por la compatibilidad directa y la compatibilidad entre navegadores (y, por supuesto, quiero ser lo más compatible posible con los estándares).

Entonces, ¿cuál es la mejor práctica aquí? ¿Alguien puede señalar algo en la documentación DOM o en la especificación W3C que pueda resolver esto?

Tenga en cuenta que estoy específicamente interesado en una solución que no sea de biblioteca (jQuery / Prototype).

seth
fuente
Supongo que todo se reduce a que estoy buscando la forma más compatible con los estándares para acceder a un elemento de formulario utilizando el atributo de nombre ...
Seth
44
"tener ambos es algo redundante, especialmente si la identificación no es necesaria para ningún CSS, y aumenta la probabilidad de errores tipográficos" - La identificación es necesaria para el uso efectivo de las etiquetas. No solo CSS.
A veces hay múltiples formas en una página web y los atributos de identificación pueden colisionar.
Calmarius

Respuestas:

96

Déle a su formulario una identificación solamente, y su entrada solo un nombre :

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

Entonces, la manera más compatible con los estándares y menos problemática para acceder a su elemento de entrada es a través de:

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

Es preferible usar en .elements["foo"]lugar de solo .fooporque este último puede devolver una propiedad del formulario llamado "foo" en lugar de un elemento HTML.

Doin
fuente
1
@Karl ... ¿Qué estás tratando de lograr? Además del hecho de que incluir JS en su HTML es poco elegante (y a menudo ineficiente, ya que crea una función envolvente alrededor del código), el hecho de que siempre devuelva falso significa que su formulario nunca se enviará . Entonces, a menos que el formulario no esté destinado a ser enviado (tal vez sea usado completamente por el código JS), o a menos que myFunc (esto) lo envíe a través de AJAX (y no le importa hacer un envío regular como respaldo en caso de que AJAX falla de alguna manera), ... entonces has cometido un error.
Doin
1
Normalmente, para enviar solo datos de formulario válidos, haría lo siguiente: myform.onsubmit = validateForm; (donde myform es una variable que hacen referencia al elemento de formulario, y ValidateForm es el nombre de su función de validación ... pero puede que el nombre myFunc si realmente , realmente quiere ) El punto importante es que validateForm()debe devolver falso siempre que el formulario no sea válido, así como indicar los campos problemáticos al usuario. Debería volver verdadero cuando los datos del formulario se validen correctamente, lo que permitirá que la acción de envío continúe.
Doin
2
Hay otra razón para evitar identificadores en los campos de formulario: en caso de que desee varias instancias del mismo formulario (en la misma página).
koriander
1
@ João que también funciona, siempre "foo" sea válido como nombre de propiedad de JavaScript. (Puede que no sea así: HTML5 casi no impone restricciones en el valor del nameatributo, por lo que puede tener <select name="a+b">o <input type="text" name="...2">, a lo que no se puede hacer referencia mediante la notación javascript .propertyName). La notación explícita [] también permite nombres creados a partir de expresiones, por ejemplo myCheckBox = document.getElementById("myform").elements["CHK"+i]. Además, estilísticamente, creo que [] es mejor, deja en claro que estas no son solo propiedades de un objeto javascript. YMMV.
Doin
1
Con respecto al linting, tenga en cuenta que el linting es solo una guía de estilo, y un "error" no significa que su javascript sea inválido o incorrecto. Sin embargo, en este caso particular, lo que dice la regla de linting es "prefiera la notación de puntos al hacer referencia a las propiedades de objetos de JavaScript". Esa es una buena idea, y lo recomiendo en general. PERO mientras la peluquera no se da cuenta de esto,elements no es un objeto JS normal, elements.fooo elements["foo"]se está convirtiendo en elements.namedItem ("foo"). es decir, está llamando a una función definida por DOM , ¡no haciendo referencia a una propiedad JS!
Doin
34

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

" No-omg-never! " Viene a mi mente cuando veo este método de acceso a elementos. El problema con esto es que supone que el DOM es una estructura de datos normal (por ejemplo, una matriz) en la que el orden del elemento es estático, consistente o confiable de todos modos. Sabemos que el 99.9999% de las veces, ese no es el caso. Reordenar o inputelementos dentro del formulario, agregar otro forma la página antes del formulario en cuestión o mover el formulario en cuestión son todos los casos en que este código se rompe. Breve historia: esto es muy frágil. Tan pronto como agregue o mueva algo, se romperá.

[2] document.myForm.foo;

Estoy con Sergey ILinsky en esto:

  • Acceda a elementos arbitrarios haciendo referencia a su idatributo:document.getElementById("myform");
  • Acceda a los elementos de formulario con nombre por nombre, en relación con su elemento de formulario principal: document.getElementById("myform").foo;

Mi principal problema con este método es que el nameatributo es inútil cuando se aplica a un formulario. El nombre no se pasa al servidor como parte de POST / GET y no funciona para marcadores de estilo hash.

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

En mi opinión, este es el método más preferible. El acceso directo es el método más conciso y claro.

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

En mi opinión, esto es aceptable, pero más detallado de lo necesario. El método # 3 es preferible.


Por casualidad estaba viendo un video de Douglas Crockford y él intervino en este mismo tema. El punto de interés es a las -12: 00. Para resumir:

  • Las colecciones de documentos (document.anchor, document.form, etc.) son obsoletas e irrelevantes (método 1).
  • los name atributo se usa para nombrar cosas, no para acceder a ellas. Es para nombrar cosas como ventanas, campos de entrada y etiquetas de anclaje.
  • "La identificación es lo que debe usar para identificar de forma exclusiva un elemento para que pueda acceder a él. Ellos (nombre e identificación) solían ser intercambiables, pero ya no lo son".

Entonces ahí lo tienes. Semánticamente, esto tiene más sentido.

Justin Johnson
fuente
2
Entonces, ¿esto es solo un truco? document.getElementById ("myform"). foo; Después de estudiar bastante el DOM, no estoy claro por qué esto incluso funciona. Supongo que el objeto de formulario también es una matriz de sus elementos secundarios indexados en el atributo de nombre html ...
seth
1
También mencionas que "el nombre no se pasa al servidor como parte de POST / GET y no funciona para marcadores de estilo hash". ¿No es esto precisamente lo que se pasa al servidor? Cuando trabajas con PHP, el atributo de nombre es tu índice en $ _POST global.
Seth
2
@Justin, es el atributo de nombre que se pasa al servidor.
Anurag
2
@seth Las especificaciones DOM antiguas parecen muy vagas sobre por qué document.aForm.foofunciona, pero la especificación HTML5 parece definir claramente la interfaz de una HTMLFormElementque tiene caller getter any namedItem(in DOMString name);. Más en whatwg.org/specs/web-apps/current-work/multipage/…
Anurag
1
@ ambos: "... el atributo de nombre es inútil cuando se aplica a un formulario ..." No estoy hablando del atributo de nombre de un inputo select, estoy hablando del atributo de nombre de a form. El atributo de nombre de a form no se pasa al servidor.
Justin Johnson
14

Para acceder a los elementos con nombre ubicados en un formulario, es una buena práctica usar el formobjeto en sí.

Para acceder a un elemento arbitrario en el árbol DOM que en ocasiones se puede encontrar dentro de un formulario, use getElementByIdy el elemento id.

Sergey Ilinsky
fuente
8
¿Qué quiere decir "usar objeto de formulario en sí mismo"? Una vez que tiene el objeto de formulario, ¿qué método utiliza para acceder a un elemento en particular?
Seth
2
Quiero decir que recomendaría usar N5 (document.getElementById ('myForm'). Elements.foo) para acceder a elementos con nombre y N6 (document.getElementById ('myForm'). Elementos) para acceder a la colección iterable de elementos
Sergey Ilinsky
Estoy definiendo el estilo de mi código ... y, como preferencia, me quedo con los ID ... de esa manera el acceso al elemento es consistente en toda la página. + las otras razones mencionadas.
1
¿Por qué es una buena práctica acceder al formulario usando getElementID? ¿por qué document.myForm no funciona? (Tengo una situación en la que no funciona y me pregunto por qué)
Spundun
Hola Spundun, probablemente resolviste tu problema hace meses (o tal vez levantaste las manos :)), pero en caso de que te lo estés preguntando, probablemente se deba a que no proporcionaste tu elemento HTML del formulario con un atributo "nombre".
Sheldon R.
8

Prefiero un quinto método. Es decir
[5] Utilice el identificador especial de JavaScript este para pasar el objeto de formulario o campo a la función de controlador de eventos.

Específicamente, para formularios:

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

y

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

Usando esta técnica, la función nunca tiene que saber
: el orden en que se definen los formularios en la página,
- el ID del formulario, ni
- el nombre del formulario

Del mismo modo, para los campos:

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

y

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;
}

En este caso, la función nunca tiene que conocer el nombre o la identificación de un campo de peso en particular, aunque sí necesita saber el nombre del campo de límite de peso.

Robin Richmond
fuente
No estoy seguro de cuál es la causa subyacente, pero he tenido este enfoque que devuelve cadenas vacías en algunas, pero no en todas, las circunstancias.
Jacob Lee
7

Realmente no está respondiendo tu pregunta, sino solo en esta parte:

[3] requiere una identificación y un nombre ... tener ambos es algo redundante

De idtodos modos, lo más probable es que necesite tener un atributo en cada campo de formulario, de modo que pueda asociar su <label>elemento con él, así:

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

Esto es necesario para la accesibilidad (es decir, si no asocia etiquetas de formulario y controles, ¿por qué odia tanto a las personas ciegas?).

Es algo redundante, aunque menos cuando tiene casillas de verificación / botones de radio, donde varios de ellos pueden compartir a name. En última instancia, idy nameson para diferentes propósitos, incluso si ambos se establecen a menudo en el mismo valor.

Paul D. Waite
fuente
55
Si ajusta una entrada en su etiqueta, no necesita una identificación o un atributo for. <label> Foo: <input type = "text" name = "foo" </label>
kennebec
3
Muy cierto, aunque eso limita lo que puedes lograr en términos de apariencia.
Paul D. Waite
2
@ kennebec: siempre debe usar una identificación si desea que la etiqueta se asocie con un elemento. Las versiones anteriores de IE (<8?) No elementos asociados dentro de una etiqueta con la etiqueta, si no había haciendo juego para y id atributos.
RobG
Además de lo que escribió @kennebec, el uso de ID crea JS globales y debe evitarse.
mikemaccana
1
@mikemaccana: He visto que eso causa problemas antes. Creo que si sus ID son razonablemente descriptivas y su JavaScript tiene un espacio de nombres razonable, es poco probable que cause problemas.
Paul D. Waite
6

Esto es un poco viejo pero quiero agregar algo que creo que es relevante.
(Tenía la intención de comentar en uno o 2 hilos anteriores, pero parece que necesito reputación 50 y solo tengo 21 en el momento en que escribo esto. :))
Solo quiero decir que hay momentos en que es mucho mejor acceder al elementos de un formulario por nombre en lugar de por id. No estoy hablando de la forma en sí. El formulario, OK, puede asignarle una identificación y luego acceder a él. Pero si tiene un botón de radio en un formulario, es mucho más fácil usarlo como un solo objeto (obtener y establecer su valor) y solo puede hacerlo por nombre, que yo sepa.

Ejemplo:

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

Puede obtener / establecer el valor marcado del botón de opción R1 en su conjunto mediante
document.mainForm.R1.value
o
document.getElementById ("mainForm"). R1.value
Entonces, si desea tener un estilo unitario, puede desea utilizar siempre este método, independientemente del tipo de elemento de formulario. Yo, estoy perfectamente cómodo accediendo a los botones de radio por nombre y cuadros de texto por id.

VSim
fuente
Lo que funciona es document.forms.mainForm.R1.value, que de hecho es una buena manera de evitar el uso del tipo feo y tediosodocument.getElementById()
Kai Carver
2

Siendo anticuado, siempre he usado la sintaxis 'document.myform.myvar' pero recientemente encontré que falló en Chrome (OK en Firefox e IE). Era una página Ajax (es decir, cargada en la propiedad innerHTML de un div). Quizás Chrome no reconoció el formulario como un elemento del documento principal. En su lugar, utilicé getElementById (sin hacer referencia al formulario) y funcionó bien.

Capitán nemo
fuente
simplemente puede insertar .forms, así que document.forms.myform.myvar
Kai Carver
1

Solo para agregar a todo lo que ya se dijo, puede acceder a los inputmensajes de correo electrónico con nameo idusando preferiblemente la elementspropiedad del formulario Objeto, porque sin él puede obtener una propiedad del formulario llamado "foo" en lugar de un elemento HTML. Y de acuerdo con @Paul D. Waite, está perfectamente bien tener tanto el nombre como la identificación.

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>

De acuerdo con MDN en la página HTMLFormElement.elements

Los elementos de propiedad HTMLFormElement devuelven una HTMLFormControlsCollection que enumera todos los controles de formulario contenidos en el elemento. Independientemente, puede obtener solo el número de controles de formulario utilizando la propiedad de longitud.

Puede acceder a un control de formulario particular en la colección devuelta utilizando un índice o el nombre o id del elemento .

João Pimentel Ferreira
fuente
1

nameEl campo funciona bien. Proporciona una referencia a la elements.

parent.children- Listará todos los elementos con un campo de nombre del padre. parent.elements- Listará solo form elementscomoinput-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>

Nota: Para .elementstrabajar, la parentnecesidad debe ser a <form> tag. Mientras que, .childrenfuncionará en cualquiera HTML-element, como<div>, <span>, etc .

Buena suerte...

Akash
fuente
0

El formulario 2 está bien y también se recomienda el formulario 3.
La redundancia entre el nombre y la identificación es causada por la necesidad de mantener la compatibilidad, en html 5 algunos elementos (como img, form, iframe y demás) perderán su atributo "nombre", y se recomienda usar solo su identificación para hacer referencia a ellos a partir de ahora. en :)

invierno
fuente
Parece que los elementos de entrada nunca perderán su atributo de nombre debido a la forma en que lo usan los idiomas del lado del servidor. Entonces la pregunta sigue siendo, ¿cuál es el método que cumple con los estándares si solo tiene configurado el atributo de nombre?
Seth
En un desarrollo que cumpla con los estándares, no solo tendría el nombre, para empezar. Si realmente NO PUEDE tener ID, entonces sugeriría la función document.getElementByName ().
wintermute
0

Para complementar las otras respuestas, document.myForm.foo es el llamado DOM nivel 0, que es la forma implementada por Netscape y, por lo tanto, no es realmente un estándar abierto a pesar de que es compatible con la mayoría de los navegadores.

Kent Tong
fuente
44
Acceder a formularios y controles de formulario por nombre, id e índice es parte del estándar HTML DOM 2 para colecciones HTML .
RobG
0

Echa un vistazo a esta página: https://developer.mozilla.org/En/DOM/Document.getElementsByName

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

Tiene que ser 'elementos' y debe devolver una matriz porque más de un elemento podría tener el mismo nombre.

robert
fuente
@robert, ahora estoy pensando que esta podría ser una buena solución, aunque esto directamente de los documentos me puso nervioso: "Este método podría ser cuestionable para su uso dados los cambios anteriores entre los tipos de documentos y el comportamiento no estándar actual para esto método en XHTML ".
Seth
Hola. ¿Qué documentación sugerida en contra de esto? Creo que si está utilizando xhtml en todos los entornos DOM en los que está trabajando, entonces debería estar bien. Además, ¿qué navegadores no admiten esto? Aquí están los documentos para IE: msdn.microsoft.com/en-us/library/ms536438(VS.85).aspx Además de Mozilla anterior, ¿quién más podría no admitirlo?
robert
0

Mi respuesta diferirá en la pregunta exacta. Si quiero acceder a un determinado elemento específicamente, entonces usaré document.getElementById (). Un ejemplo es calcular el nombre completo de una persona, porque se basa en múltiples campos, pero es una fórmula repetible.

Si quiero acceder al elemento como parte de una estructura funcional (un formulario), entonces usaré:

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

Así es como también funciona desde la perspectiva del negocio. Los cambios dentro del ciclo van junto con los cambios funcionales en la aplicación y, por lo tanto, son significativos. Lo aplico principalmente para una validación fácil de usar y para evitar llamadas de red para verificar datos incorrectos. Repito el lado del servidor de validación (y agrego un poco más), pero si puedo ayudar al lado del cliente, entonces eso es beneficioso para todos.

Para la agregación de datos (como construir un gráfico circular basado en datos en el formulario), uso documentos de configuración y objetos Javascript personalizados. Entonces, el significado exacto del campo es importante en relación con su contexto y utilizo document.getElementById ().

Loek Bergman
fuente
0

Porque el caso [2] document.myForm.fooes un dialecto de Internet Exploere. Entonces, en lugar de eso, prefiero document.forms.myForm.elements.fooo document.forms["myForm"].elements["foo"].

takahar tanak
fuente
-1

Prefiero éste

document.forms['idOfTheForm'].nameOfTheInputFiled.value;
Fahim Md. Riaz
fuente
2
Bienvenido a SO, apreciamos su aporte. Edite su respuesta y explique por qué y cómo.
B - rian