Best practice: accedi agli elementi del modulo tramite ID HTML o attributo name?


136

Come ogni sviluppatore JavaScript esperto sa, ci sono molti (troppi) modi per fare la stessa cosa. Ad esempio, supponi di avere un campo di testo come segue:

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

Esistono molti modi per accedervi in ​​JavaScript:

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

I metodi [1] e [3] sono ben documentati nella documentazione di Mozilla Gecko, ma nessuno dei due è l'ideale. [1] è troppo generico per essere utile e [3] richiede sia un ID che un nome (supponendo che pubblichi i dati in una lingua lato server). Idealmente, sarebbe meglio avere solo un attributo id o un attributo name (avendo entrambi lo è qualche modo ridondante, specialmente se l'id non è necessario per qualsiasi CSS, e aumenta la probabilità di errori di battitura, ecc.).

[2] sembra essere il più intuitivo e sembra essere ampiamente usato, ma non l'ho visto menzionato nella documentazione di Gecko e sono preoccupato sia per la compatibilità con i forward che per quella tra browser (e ovviamente voglio essere il più possibile conforme agli standard).

Quindi qual è la migliore pratica qui? Qualcuno può indicare qualcosa nella documentazione DOM o specifica W3C che potrebbe risolvere questo?

Nota Sono particolarmente interessato a una soluzione non di libreria (jQuery / Prototype).


Immagino che ciò che si riduce è che sto cercando il modo più conforme agli standard per accedere a un elemento del modulo utilizzando l'attributo name ...
seth

4
"avere entrambi è in qualche modo ridondante, specialmente se l'id non è necessario per alcun CSS, e aumenta la probabilità di errori di battitura" - ID è necessario per un uso efficace delle etichette. Non solo CSS.

A volte ci sono più moduli in una pagina Web e gli attributi ID possono scontrarsi.
Calmarius,

Risposte:


96

Assegna al tuo modulo solo un ID e inserisci solo un nome :

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

Quindi il modo più conforme agli standard e meno problematico per accedere al tuo elemento di input è tramite:

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

usare .elements["foo"]invece di just .fooè preferibile perché quest'ultimo potrebbe restituire una proprietà del modulo chiamato "pippo" piuttosto che un elemento HTML!


1
@Karl ... Cosa stai cercando di ottenere? A parte il fatto che l'integrazione di JS nel tuo HTML è piuttosto inelegante (e spesso inefficiente, poiché crea una funzione wrapper attorno al codice), il fatto che tu restituisca sempre false significa che il tuo modulo non verrà mai inviato. Quindi, a meno che il modulo non sia destinato a essere inviato (forse è utilizzato interamente dal codice JS) o a meno che myFunc (questo) lo invii tramite AJAX (e non ti interessa fare un invio regolare come fallback nel caso AJAX fallisce in qualche modo), ... allora hai fatto un errore.
Doin,

1
Normalmente, a presentare solo i dati valida forma, faresti: myform.onsubmit = validateForm;(dove MyForm è una variabile che fa riferimento alla elemento form, e ValidateForm è il nome della funzione di convalida ... ma si può chiamarlo myFunc se davvero , davvero vuoi ). Il punto importante è che validateForm()dovrebbe restituire false ogni volta che il modulo non è valido, oltre a indicare i campi del problema all'utente. Dovrebbe restituire true quando i dati del modulo vengono convalidati correttamente, il che consentirà di proseguire l'azione di invio.
Doin,

2
C'è un altro motivo per evitare ID nei campi modulo: nel caso in cui si desideri più istanze dello stesso modulo (nella stessa pagina).
koriander,

1
@ João funziona anche a condizione che "pippo" sia valido come nome di proprietà javascript. (Potrebbe non essere - HTML5 non pone quasi alcuna restrizione sul valore namedell'attributo, quindi ad esempio puoi avere <select name="a+b">o <input type="text" name="...2">, a cui non puoi fare riferimento usando la notazione javascript .propertyName). La notazione esplicita [] consente anche nomi creati da espressioni, ad es myCheckBox = document.getElementById("myform").elements["CHK"+i]. Inoltre, dal punto di vista stilistico, penso che [] sia migliore - chiarisce che queste non sono solo proprietà di un oggetto javascript. YMMV.
Doin,

1
Per quanto riguarda la lanugine, tieni presente che la lanugine è solo una guida di stile e un "errore" di lanugine non significa che il tuo javascript non sia valido o errato. In questo caso particolare, tuttavia, ciò che la regola del linting sta dicendo è "preferisci la notazione punto quando si fa riferimento alle proprietà dell'oggetto javascript". È una buona idea, e lo consiglio in generale. MA mentre il linter non si rende conto questo, elementsnon è un oggetto normale JS, e elements.fooo elements["foo"]è in realtà sempre convertito in elements.namedItem ( "foo"). cioè stai chiamando una funzione definita dal DOM , senza fare riferimento a una proprietà JS!
Doin,

34

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

" No-omg-never! " Mi viene in mente quando vedo questo metodo di accesso agli elementi. Il problema è che si presume che il DOM sia una normale struttura di dati (ad es. Un array) in cui l'ordine degli elementi è comunque statico, coerente o affidabile. Sappiamo che il 99,9999% delle volte non è così. Il riordino o gli inputelementi all'interno del modulo, l'aggiunta di un altro formalla pagina prima del modulo in questione o lo spostamento del modulo in questione sono tutti casi in cui questo codice si interrompe. Racconto: questo è molto fragile. Non appena aggiungi o sposti qualcosa, si romperà.

[2] document.myForm.foo;

Sono con Sergey ILinsky su questo:

  • Accedi a elementi arbitrari facendo riferimento al loro idattributo:document.getElementById("myform");
  • Accedi agli elementi del modulo con nome per nome, in relazione al loro elemento del modulo principale: document.getElementById("myform").foo;

Il mio problema principale con questo metodo è che l' nameattributo è inutile quando applicato a un modulo. Il nome non viene passato al server come parte di POST / GET e non funziona per i segnalibri in stile hash.

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

Secondo me, questo è il metodo più preferibile. L'accesso diretto è il metodo più conciso e chiaro.

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

Secondo me, questo è accettabile, ma più dettagliato del necessario. Il metodo n. 3 è preferibile.


Mi è capitato di vedere un video di Douglas Crockford e ha approfondito questo argomento. Il punto di interesse è a -12: 00. Riassumere:

  • Le raccolte di documenti (document.anchor, document.form, ecc.) Sono obsolete e irrilevanti (metodo 1).
  • L' nameattributo viene utilizzato per nominare le cose, non per accedervi. Serve a nominare cose come finestre, campi di input e tag di ancoraggio.
  • "L'ID è la cosa che dovresti usare per identificare univocamente un elemento in modo da poterti accedere. Loro (nome e ID) erano intercambiabili, ma non lo sono più."

Così il gioco è fatto. Semanticamente, questo ha più senso.


2
Quindi è solo un trucco? . document.getElementById ( "MyForm") foo; Dopo aver studiato un po 'il DOM, non sono chiaro sul perché questo funzioni. La mia ipotesi è che l'oggetto modulo sia anche un array dei suoi elementi figlio indicizzati sull'attributo name html ...
seth

1
Inoltre dici "il nome non viene passato al server come parte di POST / GET e non funziona per i segnalibri in stile hash". Non è esattamente ciò che IS ha passato al server? Quando lavori con PHP, è l'attributo name che è il tuo indice nel $ _POST globale.
seth,

2
@Justin, è l'attributo name che viene passato al server.
Anurag,

2
@seth Le specifiche DOM meno recenti sembrano molto vaghe sul perché funzioni document.aForm.foo, ma le specifiche HTML5 sembrano definire chiaramente l'interfaccia di un HTMLFormElementche ha caller getter any namedItem(in DOMString name);. Altro su whatwg.org/specs/web-apps/current-work/multipage/…
Anurag

1
@ entrambi voi ragazzi: "... l'attributo name è inutile quando applicato a un modulo ..." Non sto parlando dell'attributo name di un inputo select, sto parlando dell'attributo name di a form. L'attributo name di a form non viene passato al server.
Justin Johnson,

14

Per accedere agli elementi nominati inseriti in un modulo, è buona norma utilizzare l' formoggetto stesso.

Per accedere a un elemento arbitrario nella struttura DOM che a volte può essere trovato all'interno di un modulo, utilizzare getElementByIde l'elemento id.


8
Cosa intendi con "usa l'oggetto modulo stesso"? Una volta che hai l'oggetto modulo, quale metodo usi per accedere a un particolare elemento?
seth,

2
Voglio dire che consiglierei di usare N5 (document.getElementById ('myForm'). Elements.foo) per accedere agli elementi nominati e N6 (document.getElementById ('myForm'). Elements) per accedere alla raccolta iterabile di elementi
Sergey Ilinsky

Sto definendo lo stile del mio codice ... e come preferenza mi attengo agli ID ... in questo modo l'accesso agli elementi è coerente su tutta la pagina. + gli altri motivi citati.

1
Perché è buona norma accedere al modulo utilizzando getElementID? perché document.myForm non funzionerebbe? (Ho una situazione in cui non funziona e mi chiedo perché)
Spundun,

Ehi Spundun, probabilmente hai risolto il tuo problema mesi fa (o forse hai alzato le mani :)), ma nel caso te lo stessi chiedendo, probabilmente era dovuto al fatto che non hai fornito al tuo elemento HTML del modulo un attributo "name".
Sheldon R.,

8

Preferisco di gran lunga un 5o metodo. Cioè
[5] Utilizzare l'identificatore JavaScript speciale presente per passare l'oggetto modulo o campo alla funzione dal gestore eventi.

In particolare, per i moduli:

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

e

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

Usando questa tecnica, la funzione non deve mai sapere
- l'ordine in cui i moduli sono definiti nella pagina,
- l'ID del modulo, né
- il nome del modulo

Allo stesso modo, per i campi:

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

e

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 questo caso, la funzione non deve mai conoscere il nome o l'id di un determinato campo di peso, sebbene debba conoscere il nome del campo di limite di peso.


Non sono sicuro di quale sia la causa sottostante, ma questo approccio ha restituito stringhe vuote in alcune circostanze, ma non in tutte.
Jacob Lee,

7

Non sta davvero rispondendo alla tua domanda, ma proprio da questa parte:

[3] richiede sia un ID che un nome ... avere entrambi è in qualche modo ridondante

Molto probabilmente dovrai avere un idattributo su ogni campo del modulo, in modo da poter associare il suo <label>elemento con esso, in questo modo:

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

Questo è necessario per l'accessibilità (cioè se non si associano etichette e controlli dei moduli, perché odi così tanto i non vedenti?).

È in qualche modo ridondante, sebbene meno quando si hanno caselle di controllo / pulsanti di opzione, dove molti di loro possono condividere un name. In definitiva, ide namesono per scopi diversi, anche se entrambi sono spesso impostati sullo stesso valore.


5
Se si avvolge un input nella sua etichetta, non è necessario un attributo id o for. <label> Foo: <input type = "text" name = "foo" </label>
kennebec

3
Molto vero, anche se questo limita ciò che puoi ottenere in termini di aspetto grafico.
Paul D. Waite,

2
@ kennebec — dovresti sempre usare un id se vuoi che l'etichetta sia associata ad un elemento. Le versioni precedenti di IE (<8?) Non associavano elementi all'interno di un'etichetta all'etichetta se non c'erano corrispondenze per e attributi id .
RobG

Oltre a ciò che ha scritto @kennebec, l'uso degli ID crea i globuli JS e dovrebbe essere evitato.
mikemaccana,

1
@mikemaccana: ho già visto che causano problemi in precedenza. Penso che se i tuoi ID sono ragionevolmente descrittivi e se il tuo JavaScript ha un nome ragionevole, è improbabile che causi problemi.
Paul D. Waite,

6

Questo è un po 'vecchio ma voglio aggiungere qualcosa che ritengo rilevante.
(Volevo commentare uno o 2 thread sopra, ma sembra che ho bisogno della reputazione 50 e ne ho solo 21 al momento in cui sto scrivendo questo :) :))
Voglio solo dire che ci sono momenti in cui è molto meglio accedere al elementi di una forma per nome anziché per id. Non sto parlando del modulo stesso. Il modulo, OK, puoi assegnargli un ID e poi accedervi. Ma se hai un pulsante di opzione in una forma, è molto più facile usarlo come un singolo oggetto (ottenere e impostare il suo valore) e puoi farlo solo per nome, per quanto ne so.

Esempio:

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

È possibile ottenere / impostare il valore verificato del pulsante di opzione R1 nel suo insieme utilizzando
document.mainForm.R1.value
o
document.getElementById ("mainForm"). R1.value
Quindi, se si desidera avere uno stile unitario, è possibile desidera utilizzare sempre questo metodo, indipendentemente dal tipo di elemento del modulo. Io, mi sento perfettamente a mio agio ad accedere ai pulsanti di opzione per nome e alle caselle di testo per ID.


Ciò che funziona è document.forms.mainForm.R1.value, che è davvero un bel modo per evitare di usare il brutto e noioso da scriveredocument.getElementById()
Kai Carver,

2

Essendo vecchio stile, ho sempre usato la sintassi "document.myform.myvar" ma di recente ho riscontrato che non è riuscito in Chrome (OK in Firefox e IE). Era una pagina Ajax (cioè caricata nella proprietà innerHTML di un div). Forse Chrome non ha riconosciuto il modulo come elemento del documento principale. Ho usato getElementById (senza fare riferimento al modulo) invece e ha funzionato bene.


puoi semplicemente inserire .forms, quindi document.forms.myform.myvar
Kai Carver il

1

Solo per aggiungere a tutto ciò che è già stato detto, puoi accedere a inputs con nameo idusando preferibilmente la elementsproprietà del modulo Object, perché senza di esso potresti ottenere una proprietà del modulo denominata "pippo" piuttosto che un elemento HTML. E secondo @Paul D. Waite è perfettamente ok avere sia nome che 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>

Secondo MDN nella pagina HTMLFormElement.elements

Gli elementi della proprietà HTMLFormElement restituiscono un HTMLFormControlsCollection che elenca tutti i controlli del modulo contenuti nell'elemento. Indipendentemente, è possibile ottenere solo il numero di controlli del modulo utilizzando la proprietà length.

È possibile accedere a un controllo modulo specifico nella raccolta restituita utilizzando un indice o il nome o l' id dell'elemento .


1

nameil campo funziona bene. Fornisce un riferimento a elements.

parent.children- Elencherà tutti gli elementi con un campo nome del genitore. parent.elements- Elencherà solo form elementscomeinput-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: .elementsper funzionare, è parentnecessario essere a <form> tag. Considerando che, .childrenfunzionerà su qualsiasi HTML-element- come ad esempio <div>, <span>, etc.

In bocca al lupo...


0

Il modulo 2 è ok e anche il modulo 3 è consigliato.
La ridondanza tra nome e ID è causata dalla necessità di mantenere la compatibilità, su html 5 alcuni elementi (come img, form, iframe e simili) perderanno il loro attributo "name", e si consiglia di usare solo il loro id per fare riferimento da ora sopra :)


Sembra che gli elementi di input non perderanno mai il loro attributo name a causa del modo in cui viene utilizzato dalle lingue lato server. Quindi la domanda rimane: qual è il metodo conforme agli standard se hai solo l'attributo name impostato?
seth,

In uno sviluppo conforme agli standard non avresti solo il nome, per cominciare. Se davvero NON PUOI avere un ID, allora suggerirei la funzione document.getElementByName ().
Wintermute

0

Per integrare le altre risposte, document.myForm.foo è il cosiddetto DOM livello 0, che è il modo implementato da Netscape e quindi non è davvero uno standard aperto anche se è supportato dalla maggior parte dei browser.


4
L'accesso ai moduli e ai controlli dei moduli per nome, ID e indice fa parte dello standard HTML DOM 2 per le raccolte HTML .
RobG

0

Dai un'occhiata a questa pagina: https://developer.mozilla.org/En/DOM/Document.getElementsByName

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

Deve essere "elementi" e deve restituire un array perché più di un elemento può avere lo stesso nome.


@robert, ora sto pensando che questa potrebbe essere una buona soluzione, anche se questo direttamente dai documenti mi ha reso nervoso: "Questo metodo potrebbe essere discutibile per l'uso date le precedenti modifiche tra i tipi di documento e l'attuale comportamento non standard per questo metodo in XHTML. "
seth

Ciao. Quale documentazione ha suggerito contro questo? Penso che se stai usando xhtml in tutti gli ambienti DOM in cui stai lavorando, allora dovresti essere OK. Inoltre, quali browser non supportano questo? Ecco i documenti per IE: msdn.microsoft.com/en-us/library/ms536438(VS.85).aspx Oltre a Mozilla sopra, chi altri potrebbe non supportarlo?
robert,

0

La mia risposta differirà sulla domanda esatta. Se voglio accedere a un determinato elemento in modo specifico, userò document.getElementById (). Un esempio è il calcolo del nome completo di una persona, poiché si basa su più campi, ma è una formula ripetibile.

Se voglio accedere all'elemento come parte di una struttura funzionale (un modulo), allora userò:

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

Funziona così anche dal punto di vista aziendale. Le modifiche all'interno del ciclo si accompagnano a modifiche funzionali nell'applicazione e sono quindi significative. Lo applico principalmente per la convalida intuitiva e la prevenzione delle chiamate di rete per il controllo di dati errati. Ripeto il lato server di convalida (e ne aggiungo un altro), ma se posso aiutare il lato client dell'utente, è vantaggioso per tutti.

Per l'aggregazione dei dati (come la creazione di un grafico a torta basato sui dati nel modulo) utilizzo documenti di configurazione e oggetti Javascript personalizzati. Quindi il significato esatto del campo è importante in relazione al suo contesto e utilizzo document.getElementById ().


0

Perché il caso [2] document.myForm.fooè un dialetto di Internet Exploere. Quindi, invece, preferisco document.forms.myForm.elements.fooo document.forms["myForm"].elements["foo"].


-1

Preferisco questo

document.forms['idOfTheForm'].nameOfTheInputFiled.value;

2
Benvenuti in SO, apprezziamo il vostro contributo. Modifica la tua risposta e spiega perché e come.
B - rian
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.