Bonne pratique: accéder aux éléments de formulaire par identifiant HTML ou attribut de nom?

136

Comme le sait tout développeur JavaScript chevronné, il existe de nombreuses (trop nombreuses) façons de faire la même chose. Par exemple, disons que vous avez un champ de texte comme suit:

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

Il existe de nombreuses façons d'y accéder en JavaScript:

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

Les méthodes [1] et [3] sont bien documentées dans la documentation de Mozilla Gecko, mais aucune n'est idéale. [1] est tout simplement trop général pour être utile et [3] nécessite à la fois un identifiant et un nom (en supposant que vous afficherez les données dans un langage côté serveur). Idéalement, il serait préférable de n'avoir qu'un attribut id ou un attribut name (avoir les deux est quelque peu redondant, surtout si l'id n'est pas nécessaire pour un css, et augmente la probabilité de fautes de frappe, etc.).

[2] semble être le plus intuitif et il semble être largement utilisé, mais je ne l'ai pas vu référencé dans la documentation de Gecko et je m'inquiète à la fois de la compatibilité ascendante et de la compatibilité entre navigateurs (et bien sûr je veux être conforme aux normes).

Alors, quelle est la meilleure pratique ici? Quelqu'un peut-il indiquer quelque chose dans la documentation DOM ou dans la spécification W3C qui pourrait résoudre ce problème?

Remarque Je suis spécifiquement intéressé par une solution non-bibliothèque (jQuery / Prototype).

seth
la source
Je suppose que cela se résume à la recherche du moyen le plus conforme aux normes d'accéder à un élément de formulaire en utilisant l'attribut name ...
seth
4
«avoir les deux est quelque peu redondant, surtout si l'id n'est pas nécessaire pour un css, et augmente la probabilité de fautes de frappe» - ID est nécessaire pour une utilisation efficace des étiquettes. Pas seulement CSS.
Parfois, il existe plusieurs formulaires sur une page Web et les attributs d'identifiant peuvent entrer en conflit.
Calmarius

Réponses:

96

Donnez à votre formulaire un identifiant uniquement et votre entrée un nom uniquement:

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

Ensuite, le moyen le plus conforme aux normes et le moins problématique d'accéder à votre élément d'entrée est via:

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

utiliser .elements["foo"]plutôt que juste .fooest préférable car ce dernier peut renvoyer une propriété de la forme nommée "foo" plutôt qu'un élément HTML!

Faire
la source
1
@Karl ... Qu'essayez-vous de réaliser? Mis à part le fait que l'inclusion de JS dans votre HTML est plutôt inélégante (et souvent inefficace, car elle crée une fonction wrapper autour du code), le fait que vous retourniez toujours false signifie que votre formulaire ne sera jamais soumis. Donc, à moins que le formulaire ne soit pas destiné à être soumis (peut-être qu'il est entièrement utilisé par le code JS), ou à moins que myFunc (this) ne le soumette via AJAX (et que vous ne vous souciez pas de faire une soumission régulière comme solution de secours au cas où AJAX échoue en quelque sorte), ... alors vous avez fait une erreur.
Fait
1
Normalement, pour présenter uniquement les données de formulaire valide, vous feriez: myform.onsubmit = validateForm;(où myform est une variable qui appelle l'élément de forme, et valideFormulaire est le nom de votre fonction de validation ... mais vous pouvez le nommer myFunc si vous vraiment , vraiment voulez ). Le point important est de validateForm()renvoyer false chaque fois que le formulaire n'est pas valide, ainsi que d'indiquer le (s) champ (s) de problème à l'utilisateur. Il doit renvoyer true lorsque les données du formulaire sont validées correctement, ce qui permettra à l'action d'envoi de se poursuivre.
Fait
2
Il y a une autre raison d'éviter les identifiants dans les champs de formulaire: au cas où vous voudriez plusieurs instances du même formulaire (dans la même page).
koriander
1
@ João qui fonctionne aussi, à condition que "foo" soit valide comme nom de propriété javascript. (Ce n'est peut-être pas le cas - HTML5 ne place pratiquement aucune restriction sur la valeur de l' nameattribut, donc par exemple, vous pouvez avoir <select name="a+b">ou <input type="text" name="...2">, qui ne peut pas être référencé en utilisant la notation javascript .propertyName). La notation explicite [] permet également de créer des noms à partir d'expressions, par exemple myCheckBox = document.getElementById("myform").elements["CHK"+i]. De plus, stylistiquement, je pense que [] est mieux - cela montre clairement que ce ne sont pas seulement les propriétés d'un objet javascript. YMMV.
Fait le
1
En ce qui concerne le peluchage, gardez à l'esprit que le peluchage n'est qu'un guide de style, et une "erreur" de peluchage ne signifie pas que votre javascript est invalide ou incorrect. Dans ce cas particulier, cependant, ce que dit la règle de linting est "préférez la notation par points lors du référencement des propriétés d'objet javascript". C'est une bonne idée, et je le recommande en général. MAIS alors que le linter ne s'en rend pas compte, elementsn'est pas un objet JS normal, et elements.fooou elements["foo"]est en train d'être converti en elements.namedItem ("foo"). c'est-à-dire que vous appelez une fonction définie par DOM , sans faire référence à une propriété JS!
Fait le
34

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

" No-omg-never! " Me vient à l'esprit quand je vois cette méthode d'accès aux éléments. Le problème avec ceci est que cela suppose que le DOM est une structure de données normale (par exemple: un tableau) dans laquelle l'ordre des éléments est statique, cohérent ou fiable de toute façon. Nous savons que 99,9999% du temps, que ce n'est pas le cas. Réorganiser des inputéléments dans le formulaire, en ajouter un autre formà la page avant le formulaire en question ou déplacer le formulaire en question sont tous les cas où ce code se brise. Petite histoire: c'est très fragile. Dès que vous ajoutez ou déplacez quelque chose, il se cassera.

[2] document.myForm.foo;

Je suis avec Sergey ILinsky à ce sujet:

  • Accédez aux éléments arbitraires en vous référant à leur idattribut:document.getElementById("myform");
  • Accédez aux éléments de formulaire nommés par leur nom, par rapport à leur élément de formulaire parent: document.getElementById("myform").foo;

Mon principal problème avec cette méthode est que l' nameattribut est inutile lorsqu'il est appliqué à un formulaire. Le nom n'est pas transmis au serveur dans le cadre du POST / GET et ne fonctionne pas pour les signets de style de hachage.

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

À mon avis, c'est la méthode la plus préférable. L'accès direct est la méthode la plus concise et la plus claire.

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

À mon avis, c'est acceptable, mais plus verbeux que nécessaire. La méthode n ° 3 est préférable.


Il se trouve que j'ai regardé une vidéo de Douglas Crockford et il a pesé sur ce sujet même. Le point d'intérêt est à -12: 00. Résumer:

  • Les collections de documents (document.anchor, document.form, etc.) sont obsolètes et non pertinentes (méthode 1).
  • L' nameattribut est utilisé pour nommer les choses, pas pour y accéder. Il sert à nommer des éléments tels que les fenêtres, les champs d'entrée et les balises d'ancrage.
  • "L'ID est la chose que vous devez utiliser pour identifier de manière unique un élément afin que vous puissiez y accéder. Ils (nom et ID) étaient interchangeables, mais ils ne le sont plus."

Alors là vous l'avez. Sémantiquement, c'est ce qui a le plus de sens.

Justin Johnson
la source
2
Alors, est-ce juste un hack? document.getElementById ("mon formulaire"). foo; Après avoir étudié un peu le DOM, je ne sais pas pourquoi cela fonctionne même. Je suppose que l'objet de formulaire est également un tableau de ses éléments enfants indexés sur l'attribut de nom html ...
seth
1
Vous mentionnez également "le nom n'est pas transmis au serveur dans le cadre du POST / GET et ne fonctionne pas pour les signets de style haché". N'est-ce pas précisément ce qui EST passé au serveur? Lorsque vous travaillez avec PHP, c'est l'attribut name qui est votre index dans le global $ _POST.
seth
2
@Justin, c'est l'attribut de nom qui est passé au serveur.
Anurag
2
@seth Les anciennes spécifications DOM semblent très vagues sur les raisons de leur document.aForm.foofonctionnement, mais la spécification HTML5 semble définir clairement l'interface d'un HTMLFormElementqui a caller getter any namedItem(in DOMString name);. Plus d'informations sur whatwg.org/specs/web-apps/current-work/multipage/…
Anurag
1
@both you: "... l'attribut name est inutile lorsqu'il est appliqué à un formulaire ..." Je ne parle pas de l'attribut name d'un inputor select, je parle de l'attribut name d'un form. L'attribut de nom de a form n'est pas transmis au serveur.
Justin Johnson
14

Pour accéder aux éléments nommés placés dans un formulaire, il est recommandé d'utiliser l' formobjet lui-même.

Pour accéder à un élément arbitraire de l'arborescence DOM qui peut parfois se trouver dans un formulaire, utilisez getElementByIdet l'élément id.

Sergey Ilinsky
la source
8
Que voulez-vous dire "utiliser l'objet du formulaire lui-même"? Une fois que vous avez l'objet de formulaire, quelle méthode utilisez-vous pour accéder à un élément particulier?
seth
2
Je veux dire, je recommanderais d'utiliser N5 (document.getElementById ('myForm'). Elements.foo) pour accéder aux éléments nommés et N6 (document.getElementById ('myForm'). Elements) pour accéder à la collection itérative d'éléments
Sergey Ilinsky
Je définis le style de mon code ... et de préférence, je m'en tiens aux identifiants ... de cette façon, l'accès aux éléments est cohérent sur toute la page. + les autres raisons évoquées.
1
Pourquoi est-il recommandé d'accéder au formulaire à l'aide de getElementID? pourquoi document.myForm ne fonctionnerait-il pas? (J'ai une situation où cela ne fonctionne pas et je me demande pourquoi)
Spundun
Hey Spundun, vous avez probablement résolu votre problème il y a des mois (ou peut-être avez-vous levé la main :)), mais au cas où vous vous poseriez la question, c'était probablement dû au fait que vous ne fournissiez pas votre élément HTML de formulaire avec un attribut "nom".
Sheldon R.
8

Je préfère de loin une 5ème méthode. C'est-à-dire
[5] Utilisez l'identifiant JavaScript spécial this pour transmettre le formulaire ou l'objet champ à la fonction à partir du gestionnaire d'événements.

Plus précisément, pour les formulaires:

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

et

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

En utilisant cette technique, la fonction n'a jamais à connaître
- l'ordre dans lequel les formulaires sont définis dans la page,
- l'ID du formulaire, ni
- le nom du formulaire

De même, pour les champs:

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

et

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

Dans ce cas, la fonction n'a jamais besoin de connaître le nom ou l'identifiant d'un champ de poids particulier, bien qu'elle ait besoin de connaître le nom du champ de limite de poids.

Robin Richmond
la source
Je ne sais pas quelle est la cause sous-jacente, mais cette approche a renvoyé des chaînes vides dans certaines circonstances, mais pas toutes.
Jacob Lee
7

Cela ne répond pas vraiment à votre question, mais juste sur cette partie:

[3] nécessite à la fois un identifiant et un nom ... avoir les deux est quelque peu redondant

Vous aurez très probablement besoin d'avoir un idattribut sur chaque champ de formulaire de toute façon, afin que vous puissiez y associer son <label>élément, comme ceci:

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

Ceci est nécessaire pour l'accessibilité (c'est-à-dire si vous n'associez pas les étiquettes de formulaire et les contrôles, pourquoi détestez-vous tant les aveugles?).

C'est quelque peu redondant, bien que moins lorsque vous avez des cases à cocher / boutons radio, où plusieurs d'entre eux peuvent partager un fichier name. En fin de compte, idet namesont à des fins différentes, même si les deux sont souvent définis sur la même valeur.

Paul D. Waite
la source
5
Si vous encapsulez une entrée dans son étiquette, vous n'avez pas besoin d'un attribut id ou for. <label> Toto: <input type = "text" name = "toto" </label>
kennebec
3
Très vrai, bien que cela limite ce que vous pouvez réaliser en termes d'apparence et de sensation.
Paul D.Waite
2
@ kennebec - vous devez toujours utiliser un identifiant si vous souhaitez que l'étiquette soit associée à un élément. Les anciennes versions d'IE (<8?) N'associaient pas les éléments à l'intérieur d'une étiquette avec l'étiquette s'il n'y avait pas de correspondance pour les attributs et id .
RobG
En plus de ce que @kennebec a écrit, l'utilisation des ID crée des globaux JS et devrait être évitée.
mikemaccana
1
@mikemaccana: J'ai déjà vu cela causer des problèmes. Je pense que si vos identifiants sont raisonnablement descriptifs et que votre JavaScript est raisonnablement espacé, il est peu probable que cela pose des problèmes.
Paul D.Waite
6

C'est un peu vieux mais je veux ajouter une chose que je pense pertinente.
(Je voulais faire des commentaires sur un ou 2 fils ci-dessus mais il semble que j'ai besoin d'une réputation de 50 et je n'en ai que 21 au moment où j'écris ceci. :))
Je veux juste dire qu'il y a des moments où il est beaucoup mieux d'accéder au éléments d'un formulaire par nom plutôt que par id. Je ne parle pas du formulaire lui-même. Le formulaire, OK, vous pouvez lui donner un identifiant et y accéder ensuite. Mais si vous avez un bouton radio dans un formulaire, il est beaucoup plus facile de l'utiliser comme un objet unique (obtenir et définir sa valeur) et vous ne pouvez le faire que par son nom, pour autant que je sache.

Exemple:

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

Vous pouvez obtenir / définir la valeur cochée du bouton radio R1 dans son ensemble en utilisant
document.mainForm.R1.value
ou
document.getElementById ("mainForm"). R1.value
Donc, si vous voulez avoir un style unitaire, vous pouvez souhaitez toujours utiliser cette méthode, quel que soit le type d'élément de formulaire. Moi, je suis parfaitement à l'aise pour accéder aux boutons radio par nom et aux zones de texte par identifiant.

VSim
la source
Ce qui fonctionne document.forms.mainForm.R1.value, c'est en effet un bon moyen d'éviter d'utiliser le moche et fastidieux à taperdocument.getElementById()
Kai Carver
2

Étant démodé, j'ai toujours utilisé la syntaxe 'document.myform.myvar' mais j'ai récemment trouvé qu'elle échouait dans Chrome (OK dans Firefox et IE). C'était une page Ajax (c'est-à-dire chargée dans la propriété innerHTML d'un div). Peut-être que Chrome n'a pas reconnu le formulaire comme un élément du document principal. J'ai utilisé getElementById (sans référencer le formulaire) à la place et cela a fonctionné correctement.

Capitaine Nemo
la source
vous pouvez simplement insérer .forms, alors document.forms.myform.myvar
Kai Carver
1

Juste pour ajouter à tout ce qui a déjà été dit, vous pouvez accéder au inputs soit avec le, namesoit en idutilisant de préférence la elementspropriété du formulaire Object, car sans cela, vous pouvez obtenir une propriété du formulaire nommée "foo" plutôt qu'un élément HTML. Et selon @Paul D. Waite, il est parfaitement normal d'avoir à la fois le nom et l'identifiant.

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>

Selon MDN sur la page HTMLFormElement.elements

Les éléments de la propriété HTMLFormElement retournent un HTMLFormControlsCollection répertoriant tous les contrôles de formulaire contenus dans l'élément. Indépendamment, vous pouvez obtenir uniquement le nombre de contrôles de formulaire à l'aide de la propriété length.

Vous pouvez accéder à un contrôle de formulaire particulier dans la collection retournée à l'aide d'un index ou du nom ou de l' ID de l'élément .

João Pimentel Ferreira
la source
1

namele terrain fonctionne bien. Il fournit une référence au elements.

parent.children- Liste tous les éléments avec un champ de nom du parent. parent.elements- Ne listera form elementsqueinput-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>

Remarque: .elementspour fonctionner, le parentdoit être un fichier <form> tag. Alors que, .childrenfonctionnera sur n'importe quel HTML-element- comme <div>, <span>, etc.

Bonne chance...

Akash
la source
0

La forme 2 est correcte et la forme 3 est également recommandée.
La redondance entre le nom et l'identifiant est causée par la nécessité de garder la compatibilité, sur html 5 certains éléments (comme img, form, iframe et autres) perdront leur attribut "name", et il est recommandé de n'utiliser que leur identifiant pour les référencer à partir de maintenant sur :)

hivermute
la source
Il semble que les éléments d'entrée ne perdront jamais leur attribut de nom en raison de la façon dont il est utilisé par les langues côté serveur. La question demeure donc, quelle est la méthode conforme aux normes si vous n'avez que l'attribut de nom défini?
seth
Dans un développement conforme aux normes, vous n'auriez pas seulement le nom, pour commencer. Si vous ne pouvez vraiment pas avoir d'ID, alors je suggérerais la fonction document.getElementByName ().
wintermute
0

Pour compléter les autres réponses, document.myForm.foo est le soi-disant niveau DOM 0, qui est la manière implémentée par Netscape et n'est donc pas vraiment un standard ouvert même s'il est pris en charge par la plupart des navigateurs.

Kent Tong
la source
4
L'accès aux formulaires et aux contrôles de formulaire par nom, identifiant et index fait partie du standard HTML DOM 2 pour les collections HTML .
RobG
0

Consultez cette page: https://developer.mozilla.org/En/DOM/Document.getElementsByName

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

Il doit s'agir d'éléments et doit renvoyer un tableau car plusieurs éléments peuvent avoir le même nom.

Robert
la source
@robert, je pense maintenant que cela pourrait être une bonne solution, même si cette sortie directe de la documentation m'a rendu nerveux: "Cette méthode pourrait être discutable pour une utilisation étant donné les changements ci-dessus entre les types de documents et le comportement non standard actuel pour cela method in XHTML. "
seth
Salut. Quelle documentation a suggéré contre cela? Je pense que si vous utilisez xhtml dans tous les environnements DOM dans lesquels vous travaillez, vous devriez être d'accord. De plus, quels navigateurs ne prennent pas en charge cela? Voici la documentation pour IE: msdn.microsoft.com/en-us/library/ms536438(VS.85).aspx En plus de Mozilla ci-dessus, qui d'autre pourrait ne pas le prendre en charge?
robert
0

Ma réponse sera différente sur la question exacte. Si je veux accéder spécifiquement à un certain élément, j'utiliserai document.getElementById (). Un exemple est le calcul du nom complet d'une personne, car il s'appuie sur plusieurs champs, mais c'est une formule répétable.

Si je souhaite accéder à l'élément dans le cadre d'une structure fonctionnelle (un formulaire), je vais utiliser:

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

C'est ainsi que cela fonctionne également du point de vue de l'entreprise. Les changements dans la boucle s'accompagnent de changements fonctionnels dans l'application et sont donc significatifs. Je l'applique principalement pour une validation conviviale et pour empêcher les appels réseau pour vérifier des données erronées. Je répète le côté serveur de validation (et j'y ajoute un peu plus), mais si je peux aider l'utilisateur côté client, alors est-ce bénéfique pour tous.

Pour l'agrégation de données (comme la création d'un graphique à secteurs basé sur les données du formulaire), j'utilise des documents de configuration et des objets Javascript personnalisés. La signification exacte du champ est alors importante par rapport à son contexte et est-ce que j'utilise document.getElementById ().

Loek Bergman
la source
0

Parce que le cas [2] document.myForm.fooest un dialecte d'Internet Exploere. Alors au lieu de cela, je préfère document.forms.myForm.elements.fooou document.forms["myForm"].elements["foo"].

takahar tanak
la source
-1

Je préfère celui-ci

document.forms['idOfTheForm'].nameOfTheInputFiled.value;
Fahim Md. Riaz
la source
2
Bienvenue à SO, nous apprécions votre contribution. Veuillez modifier votre réponse et expliquer le pourquoi et le comment.
B - rian