Best Practice: Zugriff auf Formularelemente über HTML-ID oder Namensattribut?

136

Wie jeder erfahrene JavaScript-Entwickler weiß, gibt es viele (zu viele) Möglichkeiten, dasselbe zu tun. Angenommen, Sie haben ein Textfeld wie folgt:

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

Es gibt viele Möglichkeiten, in JavaScript darauf zuzugreifen:

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

Die Methoden [1] und [3] sind in der Mozilla Gecko-Dokumentation gut dokumentiert, aber beide sind nicht ideal. [1] ist einfach zu allgemein, um nützlich zu sein, und [3] erfordert sowohl eine ID als auch einen Namen (vorausgesetzt, Sie veröffentlichen die Daten in einer serverseitigen Sprache). Im Idealfall ist es am besten, nur ein ID-Attribut oder ein Namensattribut zu haben (beides ist etwas redundant, insbesondere wenn die ID für kein CSS erforderlich ist und die Wahrscheinlichkeit von Tippfehlern usw. erhöht).

[2] scheint am intuitivsten zu sein und es scheint weit verbreitet zu sein, aber ich habe nicht gesehen, dass in der Gecko-Dokumentation darauf verwiesen wird, und ich mache mir Sorgen um die Vorwärtskompatibilität und die Cross-Browser-Kompatibilität (und natürlich möchte ich das auch so standardkonform wie möglich).

Was ist hier die beste Vorgehensweise? Kann jemand auf etwas in der DOM-Dokumentation oder der W3C-Spezifikation verweisen, das dies beheben könnte?

Hinweis Ich bin speziell an einer Nicht-Bibliothekslösung (jQuery / Prototype) interessiert.

Seth
quelle
Ich denke, es läuft darauf hinaus, dass ich nach der standardkonformsten Möglichkeit suche, mit dem
Namensattribut
4
"Beides zu haben ist etwas redundant, insbesondere wenn die ID für kein CSS erforderlich ist und die Wahrscheinlichkeit von Tippfehlern erhöht" - ID ist für die effektive Verwendung von Labels erforderlich. Nicht nur CSS.
Manchmal gibt es mehrere Formulare auf einer Webseite und ID-Attribute können kollidieren.
Calmarius

Antworten:

96

Geben Sie Ihrem Formular nur eine ID und Ihrer Eingabe nur einen Namen :

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

Der standardkonformste und am wenigsten problematische Weg, auf Ihr Eingabeelement zuzugreifen, ist dann über:

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

Verwenden von .elements["foo"]statt nur .fooist vorzuziehen, da letztere möglicherweise eine Eigenschaft des Formulars "foo" anstelle eines HTML-Elements zurückgeben!

Doin
quelle
1
@ Karl ... Was versuchst du zu erreichen? Abgesehen von der Tatsache, dass das Inlinen von JS in Ihr HTML eher unelegant ist (und oft ineffizient ist, da es eine Wrapper-Funktion um den Code erstellt), bedeutet die Tatsache, dass Sie immer false zurückgeben, dass Ihr Formular niemals gesendet wird. Es sei denn, das Formular soll nicht gesendet werden (möglicherweise wird es vollständig vom JS-Code verwendet) oder es wird von myFunc (this) über AJAX gesendet (und es ist Ihnen egal, ob AJAX regelmäßig als Fallback gesendet wird) scheitert irgendwie), ... dann hast du einen Fehler gemacht.
Doin
1
Normalerweise werden nur gültige Formulardaten übermitteln, zu, dann würden Sie tun: myform.onsubmit = validateForm;(wo myform eine Variable ist das Formularelement Referenzierung und validateForm ist der Name Ihrer Validierungsfunktion ... aber Sie können es myFunc nennen , wenn Sie wirklich , wirklich wollen ). Der wichtige Punkt ist , dass validateForm()sollte zurückgeben falsch , wenn die Form nicht gültig ist, sowie Angabe das Problemfeldes (en) an den Benutzer. Es sollte true zurückgeben, wenn die Formulardaten korrekt validiert wurden, damit die Übermittlungsaktion ausgeführt werden kann.
Doin
2
Es gibt noch einen weiteren Grund, IDs in Formularfeldern zu vermeiden: Falls Sie mehrere Instanzen desselben Formulars (auf derselben Seite) möchten.
Koriander
1
@ João, das auch funktioniert, vorausgesetzt, "foo" ist als Javascript-Eigenschaftsname gültig. (Möglicherweise nicht - HTML5 schränkt den Wert des nameAttributs fast nicht ein , z. B. können Sie <select name="a+b">oder haben <input type="text" name="...2">, auf die mit der JavaScript-Notation .propertyName nicht verwiesen werden kann.) Die explizite [] Notation erlaubt auch Namen, die aus Ausdrücken aufgebaut sind, z myCheckBox = document.getElementById("myform").elements["CHK"+i]. Außerdem halte ich [] stilistisch für besser - es macht deutlich, dass dies nicht nur Eigenschaften eines Javascript-Objekts sind. YMMV.
Doin
1
Beachten Sie beim Flusen, dass das Flusen nur ein Styleguide ist und ein "Fehler" beim Flusen nicht bedeutet, dass Ihr Javascript ungültig oder falsch ist. In diesem speziellen Fall lautet die Flusenregel jedoch "Punktnotation bevorzugen, wenn auf Javascript-Objekteigenschaften verwiesen wird". Das ist eine gute Idee, und das empfehle ich im Allgemeinen. ABER , während die Linter dies nicht erkennen, elementsist keine normale JS Objekt und elements.foooder ist elements["foo"]eigentlich immer zu elements.namedItem umgewandelt ( „foo“). dh Sie rufen eine DOM-definierte Funktion auf und verweisen nicht auf eine JS-Eigenschaft!
Doin
34

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

" No-omg-never! " Kommt mir in den Sinn, wenn ich diese Methode des Elementzugriffs sehe. Das Problem dabei ist, dass davon ausgegangen wird, dass das DOM eine normale Datenstruktur (z. B. ein Array) ist, bei der die Elementreihenfolge in jedem Fall statisch, konsistent oder zuverlässig ist. Wir wissen, dass dies in 99,9999% der Fälle nicht der Fall ist. Neuanordnungen oder inputElemente innerhalb des Formulars, Hinzufügen eines weiteren formzur Seite vor dem betreffenden Formular oder Verschieben des betreffenden Formulars sind alles Fälle, in denen dieser Code beschädigt wird. Kurzgeschichte: Das ist sehr fragil. Sobald Sie etwas hinzufügen oder verschieben, wird es brechen.

[2] document.myForm.foo;

Ich bin mit Sergey ILinsky in diesem Punkt :

  • Greifen Sie auf beliebige Elemente zu, indem Sie auf deren idAttribut verweisen :document.getElementById("myform");
  • Greifen Sie nach Namen auf benannte Formularelemente zu, relativ zu ihrem übergeordneten Formularelement: document.getElementById("myform").foo;

Mein Hauptproblem bei dieser Methode ist, dass das nameAttribut beim Anwenden auf ein Formular unbrauchbar ist. Der Name wird nicht als Teil von POST / GET an den Server übergeben und funktioniert nicht für Lesezeichen im Hash-Stil.

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

Meiner Meinung nach ist dies die am meisten bevorzugte Methode. Der direkte Zugriff ist die präziseste und klarste Methode.

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

Meiner Meinung nach ist dies akzeptabel, aber ausführlicher als nötig. Methode 3 ist vorzuziehen.


Ich habe gerade ein Video von Douglas Crockford gesehen und er hat genau dieses Thema abgewogen. Der Punkt von Interesse ist um -12: 00. Zusammenfassen:

  • Dokumentensammlungen (document.anchor, document.form usw.) sind veraltet und irrelevant (Methode 1).
  • Das nameAttribut wird verwendet, um Dinge zu benennen, nicht um darauf zuzugreifen. Es dient zum Benennen von Fenstern, Eingabefeldern und Ankertags.
  • "ID ist das, was Sie verwenden sollten, um ein Element eindeutig zu identifizieren, damit Sie darauf zugreifen können. Früher waren sie (Name und ID) austauschbar, aber sie sind nicht mehr vorhanden."

Da haben Sie es also. Semantisch ist dies am sinnvollsten.

Justin Johnson
quelle
2
Also ist das nur ein Hack? document.getElementById ("myform"). foo; Nach einigem Studium des DOM bin ich mir nicht sicher, warum das überhaupt funktioniert. Ich vermute, das Formularobjekt ist auch ein Array seiner
untergeordneten
1
Sie erwähnen auch "Der Name wird nicht als Teil des POST / GET an den Server übergeben und funktioniert nicht für Lesezeichen im Hash-Stil". Ist das nicht genau das, was an den Server übergeben wird? Wenn Sie mit PHP arbeiten, ist das Namensattribut Ihr Index im globalen $ _POST.
Seth
2
@ Justin, es ist das Namensattribut, das an den Server übergeben wird.
Anurag
2
@seth Die älteren DOM-Spezifikationen scheinen sehr vage zu sein, warum dies document.aForm.foofunktioniert, aber die HTML5-Spezifikation scheint die Schnittstelle eines, HTMLFormElementdas hat , klar zu definieren caller getter any namedItem(in DOMString name);. Mehr unter whatwg.org/specs/web-apps/current-work/multipage/…
Anurag
1
@both euch: "... das Namensattribut ist nutzlos, wenn es auf ein Formular angewendet wird ..." Ich spreche nicht über das Namensattribut eines inputoder select, ich spreche über das Namensattribut eines form. Das Namensattribut von a form wird nicht an den Server übergeben.
Justin Johnson
14

Um auf benannte Elemente in einem Formular zuzugreifen, empfiehlt es sich, das formObjekt selbst zu verwenden.

Verwenden Sie getElementByIdund das Element , um auf ein beliebiges Element im DOM-Baum zuzugreifen, das sich gelegentlich in einem Formular befindet id.

Sergey Ilinsky
quelle
8
Was meinst du mit "Formularobjekt selbst verwenden"? Mit welcher Methode greifen Sie auf ein bestimmtes Element zu, wenn Sie das Formularobjekt haben?
Seth
2
Ich würde empfehlen, N5 (document.getElementById ('myForm'). Elements.foo) zu verwenden, um auf benannte Elemente zuzugreifen, und N6 (document.getElementById ('myForm'). Elements), um auf die iterierbare Auflistung von Elementen
zuzugreifen
Ich definiere den Stil meines Codes ... und halte mich vorzugsweise an IDs ... auf diese Weise ist der Elementzugriff auf der gesamten Seite konsistent. + die anderen genannten Gründe.
1
Warum empfiehlt es sich, mit getElementID auf das Formular zuzugreifen? Warum sollte document.myForm nicht funktionieren? (Ich habe eine Situation, in der es nicht funktioniert und ich frage mich warum)
Spundun
Hey Spundun, Sie haben Ihr Problem wahrscheinlich vor Monaten gelöst (oder Sie haben Ihre Hände hochgeworfen :)), aber falls Sie sich gefragt haben, lag es wahrscheinlich daran, dass Sie Ihrem Formular-HTML-Element kein "Name" -Attribut zur Verfügung gestellt haben.
Sheldon R.
8

Ich bevorzuge eine 5. Methode. Das heißt
[5] mit dem Spezial JavaScript Kennung dies die Form oder das Feld von der Ereignisbehandlungsroutine für die Funktion Objekt zu übergeben.

Speziell für Formulare:

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

und

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

Mit dieser Technik muss die Funktion niemals wissen
- in welcher Reihenfolge Formulare auf der Seite definiert sind,
- die Formular-ID oder
- den Formularnamen

Ebenso für Felder:

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

und

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 diesem Fall muss die Funktion niemals den Namen oder die ID eines bestimmten Gewichtsfelds kennen, obwohl sie den Namen des Gewichtsbegrenzungsfelds kennen muss.

Robin Richmond
quelle
Ich bin mir nicht sicher, was die zugrunde liegende Ursache ist, aber ich habe diesen Ansatz unter einigen, aber nicht allen Umständen leere Zeichenfolgen zurückgeben lassen.
Jacob Lee
7

Es beantwortet Ihre Frage nicht wirklich, sondern nur in diesem Teil:

[3] erfordert sowohl eine ID als auch einen Namen ... beides zu haben ist etwas redundant

Wahrscheinlich müssen idSie ohnehin ein Attribut für jedes Formularfeld haben, damit Sie das <label>Element wie folgt zuordnen können :

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

Dies ist für die Barrierefreiheit erforderlich (dh wenn Sie keine Formularbezeichnungen und Steuerelemente zuordnen, warum hassen Sie Blinde so sehr?).

Es ist etwas redundant, wenn auch weniger, wenn Sie Kontrollkästchen / Optionsfelder haben, von denen mehrere eine gemeinsam nutzen können name. Letztendlich idund namefür unterschiedliche Zwecke, auch wenn beide oft auf den gleichen Wert eingestellt sind.

Paul D. Waite
quelle
5
Wenn Sie eine Eingabe in ihre Bezeichnung einschließen, benötigen Sie weder eine ID noch ein for-Attribut. <label> Foo: <input type = "text" name = "foo" </ label>
kennebec
3
Sehr wahr, obwohl dies das einschränkt, was Sie in Bezug auf das Erscheinungsbild erreichen können.
Paul D. Waite
2
@ kennebec - Sie sollten immer eine ID verwenden, wenn die Beschriftung einem Element zugeordnet werden soll. Ältere Versionen von IE (<8?) Ordneten dem Label keine Elemente innerhalb eines Labels zu, wenn keine übereinstimmenden Attribute für und id vorhanden waren .
RobG
Zusätzlich zu dem, was @kennebec geschrieben hat, werden durch die Verwendung von IDs JS-Globals erstellt, die vermieden werden sollten.
Mikemaccana
1
@mikemaccana: Ich habe gesehen, dass dies Probleme verursacht. Ich denke, wenn Ihre IDs einigermaßen beschreibend sind und Ihr JavaScript einen vernünftigen Namespace aufweist, ist es jedoch unwahrscheinlich, dass dies zu Problemen führt.
Paul D. Waite
6

Das ist ein bisschen alt, aber ich möchte etwas hinzufügen, das ich für relevant halte.
(Ich wollte einen oder zwei Threads oben kommentieren, aber es scheint, dass ich den Ruf 50 brauche und zum Zeitpunkt des Schreibens nur 21 habe. :)) Ich
möchte nur sagen, dass es Zeiten gibt, in denen es viel besser ist, auf den zuzugreifen Elemente eines Formulars nach Namen und nicht nach ID. Ich spreche nicht über das Formular selbst. Das Formular, OK, Sie können ihm eine ID geben und dann darauf zugreifen. Wenn Sie jedoch ein Optionsfeld in einem Formular haben, ist es viel einfacher, es als einzelnes Objekt zu verwenden (Abrufen und Festlegen seines Werts), und Sie können dies meines Wissens nur mit Namen tun.

Beispiel:

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

Sie können den aktivierten Wert des Optionsfelds R1 als Ganzes abrufen / festlegen, indem Sie
document.mainForm.R1.value
oder
document.getElementById ("mainForm") verwenden. R1.value
Wenn Sie also einen einheitlichen Stil haben möchten, können Sie dies tun Ich möchte diese Methode immer verwenden, unabhängig vom Typ des Formularelements. Ich bin sehr zufrieden damit, auf Optionsfelder nach Namen und Textfelder nach ID zuzugreifen.

VSim
quelle
Was funktioniert, ist document.forms.mainForm.R1.value, was in der Tat eine gute Möglichkeit ist , die Verwendung des hässlichen und langwierigen Typs zu vermeidendocument.getElementById()
Kai Carver
2

Da ich altmodisch bin, habe ich immer die Syntax 'document.myform.myvar' verwendet, aber ich habe kürzlich festgestellt, dass sie in Chrome fehlgeschlagen ist (OK in Firefox und IE). Es war eine Ajax-Seite (dh in die innerHTML-Eigenschaft eines div geladen). Möglicherweise hat Chrome das Formular nicht als Element des Hauptdokuments erkannt. Ich habe stattdessen getElementById verwendet (ohne auf das Formular zu verweisen) und es hat in Ordnung funktioniert.

Kapitän Nemo
quelle
Sie können einfach einfügen .forms, also document.forms.myform.myvar
Kai Carver
1

Um alles bereits Gesagte zu ergänzen, können Sie inputentweder mit der Eigenschaft nameoder idvorzugsweise mit der elementsEigenschaft des Objektformulars auf das s zugreifen , da Sie ohne diese Eigenschaft möglicherweise eine Eigenschaft des Formulars mit dem Namen "foo" anstelle eines HTML-Elements erhalten. Und laut @Paul D. Waite ist es vollkommen in Ordnung, sowohl Namen als auch ID zu haben.

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>

Laut MDN auf der Seite HTMLFormElement.elements

Die HTMLFormElement-Eigenschaftselemente geben eine HTMLFormControlsCollection zurück, in der alle im Element enthaltenen Formularsteuerelemente aufgelistet sind. Unabhängig davon können Sie mit der Eigenschaft length nur die Anzahl der Formularsteuerelemente abrufen.

Sie können auf ein bestimmtes Formularsteuerelement in der zurückgegebenen Auflistung zugreifen, indem Sie entweder einen Index oder den Namen oder die ID des Elements verwenden .

João Pimentel Ferreira
quelle
1

nameFeld funktioniert gut. Es enthält einen Verweis auf die elements.

parent.children- Listet alle Elemente mit einem Namensfeld des übergeordneten Elements auf. parent.elements- Wird nur form elementssolche wie auflisteninput-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>

Hinweis: Damit Sie .elementsarbeiten können, parentmuss a <form> tag. Während .childrenwird auf jedem arbeiten HTML-element- wie <div>, <span>, etc.

Viel Glück...

Akash
quelle
0

Form 2 ist in Ordnung und Form 3 wird ebenfalls empfohlen.
Die Redundanz zwischen Name und ID wird durch die Notwendigkeit verursacht, die Kompatibilität beizubehalten. Unter HTML 5 verlieren einige Elemente (wie img, form, iframe usw.) ihr Attribut "name". Es wird empfohlen, ab sofort nur ihre ID zu verwenden, um auf sie zu verweisen auf :)

Wintermute
quelle
Es scheint, dass Eingabeelemente aufgrund der Verwendung durch serverseitige Sprachen niemals ihr Namensattribut verlieren. Es bleibt also die Frage, was ist die standardkonforme Methode, wenn Sie nur das Namensattribut festgelegt haben?
Seth
In einer standardkonformen Entwicklung hätten Sie zunächst nicht nur den Namen. Wenn Sie wirklich keine ID haben können, würde ich die Funktion document.getElementByName () vorschlagen.
Wintermute
0

Als Ergänzung zu den anderen Antworten ist document.myForm.foo die sogenannte DOM-Ebene 0, die von Netscape implementiert wird und daher kein wirklich offener Standard ist, obwohl sie von den meisten Browsern unterstützt wird.

Kent Tong
quelle
4
Der Zugriff auf Formulare und Formularsteuerelemente über Name, ID und Index ist Teil des DOM 2-HTML-Standards für HTML-Sammlungen .
RobG
0

Schauen Sie sich diese Seite an: https://developer.mozilla.org/En/DOM/Document.getElementsByName

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

Es muss 'Elemente' sein und ein Array zurückgeben, da mehr als ein Element denselben Namen haben kann.

Robert
quelle
@robert, ich denke jetzt, dass dies eine gute Lösung sein könnte, obwohl mich dies direkt aus den Dokumenten heraus nervös machte: "Diese Methode könnte angesichts der oben genannten Änderungen zwischen Dokumenttypen und des aktuellen nicht standardmäßigen Verhaltens für die Verwendung fraglich sein Methode in XHTML. "
Seth
Hallo. Welche Dokumentation schlug dagegen vor? Ich denke, wenn Sie xhtml in allen DOM-Umgebungen verwenden, in denen Sie arbeiten, sollten Sie in Ordnung sein. Welche Browser unterstützen dies nicht? Hier sind die Dokumente für den Internet Explorer : msdn.microsoft.com/en-us/library/ms536438(VS.85).aspx Wer unterstützt sie möglicherweise zusätzlich zu Mozilla oben nicht?
Robert
0

Meine Antwort wird sich in der genauen Frage unterscheiden. Wenn ich speziell auf ein bestimmtes Element zugreifen möchte, verwende ich document.getElementById (). Ein Beispiel ist die Berechnung des vollständigen Namens einer Person, da diese auf mehreren Feldern aufbaut, es sich jedoch um eine wiederholbare Formel handelt.

Wenn ich als Teil einer Funktionsstruktur (eines Formulars) auf das Element zugreifen möchte, verwende ich:

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

So funktioniert das auch aus geschäftlicher Sicht. Änderungen innerhalb der Schleife gehen mit funktionalen Änderungen in der Anwendung einher und sind daher von Bedeutung. Ich wende es hauptsächlich zur benutzerfreundlichen Validierung und zur Verhinderung von Netzwerkanrufen zur Überprüfung falscher Daten an. Ich wiederhole die Validierungsserverseite (und füge dort noch etwas hinzu), aber wenn ich der Benutzerclientseite helfen kann, ist das für alle von Vorteil.

Für die Aggregation von Daten (wie das Erstellen eines Kreisdiagramms basierend auf Daten im Formular) verwende ich Konfigurationsdokumente und benutzerdefinierte Javascript-Objekte. Dann ist die genaue Bedeutung des Feldes in Bezug auf seinen Kontext wichtig und verwende ich document.getElementById ().

Loek Bergman
quelle
0

Weil der Fall [2] document.myForm.fooein Dialekt von Internet Exploere ist. Also stattdessen bevorzuge ich document.forms.myForm.elements.foooder document.forms["myForm"].elements["foo"].

Takahar Tanak
quelle
-1

Ich bevorzuge dieses hier

document.forms['idOfTheForm'].nameOfTheInputFiled.value;
Fahim Md. Riaz
quelle
2
Willkommen bei SO, wir freuen uns über Ihre Beiträge. Bitte bearbeiten Sie Ihre Antwort und erklären Sie das Warum und Wie.
B - rian