Najlepsza praktyka: uzyskać dostęp do elementów formularza za pomocą identyfikatora HTML lub atrybutu nazwy?


136

Jak wie każdy doświadczony programista JavaScript, istnieje wiele (zbyt wiele) sposobów na zrobienie tego samego. Na przykład załóżmy, że masz następujące pole tekstowe:

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

Istnieje wiele sposobów uzyskania dostępu do tego w JavaScript:

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

Metody [1] i [3] są dobrze udokumentowane w dokumentacji Mozilla Gecko, ale żadna z nich nie jest idealna. [1] jest po prostu zbyt ogólne, aby było użyteczne, a [3] wymaga zarówno identyfikatora, jak i nazwy (zakładając, że będziesz wysyłać dane do języka po stronie serwera). Najlepiej byłoby mieć tylko atrybut id lub atrybut nazwy (posiadanie obu jest nieco zbędne, zwłaszcza jeśli identyfikator nie jest potrzebny do żadnego css i zwiększa prawdopodobieństwo literówek itp.).

[2] wydaje się być najbardziej intuicyjny i wydaje się być szeroko stosowany, ale nie widziałem odniesienia do niego w dokumentacji Gecko i martwię się zarówno o kompatybilność w przód, jak i kompatybilność z różnymi przeglądarkami (i oczywiście chcę być jak najbardziej zgodne z normami).

Więc jaka jest tutaj najlepsza praktyka? Czy ktoś może wskazać coś w dokumentacji DOM lub specyfikacji W3C, co mogłoby rozwiązać ten problem?

Uwaga Szczególnie interesuje mnie rozwiązanie niebędące biblioteką (jQuery / Prototype).


Wydaje mi się, że sprowadza się to do tego, że szukam najbardziej zgodnego ze standardami sposobu na dostęp do elementu formularza za pomocą atrybutu nazwy ...
seth

4
„posiadanie obu jest w pewnym sensie zbędne, zwłaszcza jeśli identyfikator nie jest potrzebny do żadnego CSS i zwiększa prawdopodobieństwo literówek” - identyfikator jest niezbędny do efektywnego wykorzystania etykiet. Nie tylko CSS.

Czasami na stronie internetowej znajduje się wiele formularzy i atrybuty identyfikatora mogą kolidować.
Calmarius,

Odpowiedzi:


96

Podaj swojemu formularzowi tylko identyfikator i wprowadź tylko nazwę :

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

Wtedy najbardziej zgodnym ze standardami i najmniej problematycznym sposobem dostępu do elementu wejściowego jest:

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

używanie .elements["foo"]zamiast just .foojest preferowane, ponieważ ta ostatnia może zwrócić właściwość formularza o nazwie „foo” zamiast elementu HTML!


1
@Karl ... Co próbujesz osiągnąć? Pomijając fakt, że wstawianie kodu JS do kodu HTML jest raczej nieeleganckie (i często nieefektywne, ponieważ tworzy funkcję opakowującą wokół kodu), fakt, że zawsze zwracasz fałsz, oznacza, że ​​formularz nigdy nie zostanie przesłany. Więc chyba, że ​​formularz nie jest przeznaczony do przesłania (być może jest używany w całości przez kod JS) lub o ile myFunc (this) nie przesyła go przez AJAX (i nie obchodzi Cię regularne przesyłanie jako rezerwowe w przypadku AJAX jakoś zawodzi), ... popełniłeś błąd.
Doin

1
Normalnie, aby złożyć tylko ważne dane formularza, można zrobić: myform.onsubmit = validateForm;(gdzie myForm jest zmienna przedstawieniu elementu formularza i validateForm jest nazwa funkcji walidacji ... ale można go nazwać myFunc jeśli naprawdę , naprawdę chcesz ). Ważną kwestią jest to, że validateForm()powinno zwracać wartość false, gdy formularz jest nieprawidłowy, a także wskazywać użytkownikowi pole (pola) powodujące problem. Powinien zwrócić wartość true, gdy dane formularza zostaną poprawnie zweryfikowane, co pozwoli na kontynuację akcji przesyłania.
Doin

2
Jest jeszcze jeden powód, aby unikać identyfikatorów w polach formularzy: na wypadek, gdybyś chciał mieć wiele instancji tego samego formularza (na tej samej stronie).
koriander

1
@ João, który też działa, pod warunkiem , że „foo” jest poprawną nazwą właściwości javascript. (Może nie - HTML5 nie nakłada prawie żadnych ograniczeń na wartość nameatrybutu, więc np. Możesz mieć <select name="a+b">lub <input type="text" name="...2">, do którego nie można się odwołać za pomocą notacji javascript .propertyName). Jawna notacja [] dopuszcza również nazwy zbudowane z wyrażeń, np myCheckBox = document.getElementById("myform").elements["CHK"+i]. Poza tym, myślę, że stylistycznie [] jest lepsze - wyjaśnia to nie tylko właściwości obiektu javascript. YMMV.
Doin

1
Jeśli chodzi o linting, pamiętaj, że linting to tylko przewodnik po stylu, a „błąd” lintingu nie oznacza, że ​​Twój JavaScript jest nieprawidłowy lub nieprawidłowy. Jednak w tym konkretnym przypadku reguła linting mówi „preferuj notację kropkową podczas odwoływania się do właściwości obiektów javascript”. To dobry pomysł i ogólnie go polecam. ALE, chociaż linter nie zdaje sobie z tego sprawy, elementsnie jest to normalny obiekt JS i elements.foolub elements["foo"]faktycznie jest konwertowany na elementy elements.namedItem ("foo"). tj jesteś wywołanie DOM zdefiniowanej funkcji , nie przedstawieniu właściwość JS!
Doin

34

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

Kiedy widzę tę metodę dostępu do elementów, przychodzi mi na myśl „ No-omg-never! ”. Problem polega na tym, że zakłada się, że DOM jest normalną strukturą danych (np. Tablicą), w której kolejność elementów jest statyczna, spójna lub niezawodna w każdym razie. Wiemy, że w 99,9999% przypadków tak nie jest. Zmiana kolejności lub inputelementy w formularzu, dodanie innego formdo strony przed danym formularzem lub przeniesienie danego formularza to przypadki, w których ten kod się zepsuje. Krótka historia: to jest bardzo delikatne. Jak tylko coś dodasz lub przeniesiesz, to się zepsuje.

[2] document.myForm.foo;

Jestem z Siergiejem Ilinskim w tej sprawie:

  • Uzyskaj dostęp do dowolnych elementów, odwołując się do ich idatrybutu:document.getElementById("myform");
  • Uzyskaj dostęp do nazwanych elementów formularza według nazwy względem ich nadrzędnego elementu formularza: document.getElementById("myform").foo;

Moim głównym problemem związanym z tą metodą jest to, że nameatrybut jest bezużyteczny, gdy jest stosowany do formularza. Nazwa nie jest przekazywana do serwera jako część POST / GET i nie działa w przypadku zakładek w stylu skrótu.

[3] document.getElementById („foo”);

Moim zdaniem jest to najkorzystniejsza metoda. Dostęp bezpośredni to najbardziej zwięzła i przejrzysta metoda.

[4] document.getElementById („myForm”). Foo;

Moim zdaniem jest to dopuszczalne, ale bardziej szczegółowe niż to konieczne. Metoda nr 3 jest preferowana.


Tak się złożyło, że obejrzałem wideo Douglasa Crockforda i on przemyślał ten temat. Punkt zainteresowania to -12: 00. Podsumowując:

  • Zbiory dokumentów (document.anchor, document.form itp.) Są przestarzałe i nieistotne (metoda 1).
  • nameAtrybut jest używany do nazwy rzeczy, aby ich nie otworzyć. Służy do nazywania rzeczy, takich jak okna, pola wejściowe i znaczniki kotwicy.
  • „Identyfikator to rzecz, której należy używać do jednoznacznej identyfikacji elementu, aby można było uzyskać do niego dostęp. Kiedyś (nazwa i identyfikator) były wymienne, ale już nie są”.

Więc masz to. Z semantycznego punktu widzenia jest to najbardziej sensowne.


2
Czy to tylko hack? document.getElementById ("myform"). foo; Po dość dokładnym przestudiowaniu DOM, nie jestem pewien, dlaczego to w ogóle działa. Domyślam się, że obiekt formularza jest także tablicą jego elementów potomnych indeksowanych w atrybucie nazwy html ...
seth

1
Wspomniałeś również, że „nazwa nie jest przekazywana do serwera jako część POST / GET i nie działa w przypadku zakładek w stylu hash”. Czy to nie jest dokładnie to, co jest przekazywane na serwer? Kiedy pracujesz z PHP, to atrybut name jest twoim indeksem w globalnej $ _POST.
seth

2
@Justin, to atrybut nazwy przekazywany do serwera.
Anurag

2
@seth Starsze specyfikacje DOM wydają się bardzo niejasne co do tego document.aForm.foo, dlaczego działa, ale specyfikacja HTML5 wydaje się jasno definiować interfejs, HTMLFormElementktóry ma caller getter any namedItem(in DOMString name);. Więcej na whatwg.org/specs/web-apps/current-work/multipage/ ...
Anurag

1
@ Oboje: „… atrybut nazwy jest bezużyteczny, gdy jest stosowany do formularza…” Nie mówię o atrybucie nazwy dla inputlub select, mówię o atrybucie nazwy dla a form. Atrybut nazwy a form nie jest przekazywany do serwera.
Justin Johnson

14

Aby uzyskać dostęp do nazwanych elementów umieszczonych w formularzu, dobrą praktyką jest użycie samego formobiektu.

Aby uzyskać dostęp do dowolnego elementu w drzewie DOM, który czasami można znaleźć w formularzu, użyj getElementByIdi elementu id.


8
Co masz na myśli „użyj samego obiektu formularza”? Gdy masz już obiekt formularza, jakiej metody używasz, aby uzyskać dostęp do określonego elementu?
seth

2
Chodzi mi o to, że zalecałbym użycie N5 (document.getElementById ('myForm'). Elements.foo), aby uzyskać dostęp do nazwanych elementów i N6 (document.getElementById ('myForm'). Elementy), aby uzyskać dostęp do iterowalnej kolekcji elementów
Sergey Ilinsky

Definiuję styl mojego kodu ... i wolę trzymać się identyfikatorów ... w ten sposób dostęp do elementów jest spójny na całej stronie. + inne wymienione powody.

1
Dlaczego dobrym zwyczajem jest uzyskiwanie dostępu do formularza przy użyciu getElementID? dlaczego document.myForm miałby nie działać? (Mam sytuację, w której to nie działa i zastanawiam się dlaczego)
Spundun

Hej Spundun, prawdopodobnie rozwiązałeś swój problem kilka miesięcy temu (a może podniosłeś ręce :)), ale jeśli się zastanawiasz, prawdopodobnie było to spowodowane tym, że nie dostarczyłeś elementowi HTML formularza z atrybutem „nazwa”.
Sheldon R.

8

O wiele bardziej wolę piątą metodę. To jest
[5] Użyj specjalnego identyfikatora JavaScript this, aby przekazać formularz lub obiekt pola do funkcji z modułu obsługi zdarzeń.

W szczególności w przypadku formularzy:

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

i

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

Korzystając z tej techniki, funkcja nigdy nie musi znać
- kolejności, w jakiej formularze są definiowane na stronie,
- ID formularza, ani
- nazwy formularza

Podobnie dla pól:

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

i

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

W tym przypadku funkcja nigdy nie musi znać nazwy ani identyfikatora konkretnego pola wagi, chociaż musi znać nazwę pola limitu wagi.


Nie jestem pewien, jaka jest przyczyna, ale mam takie podejście zwracające puste ciągi w niektórych, ale nie we wszystkich okolicznościach.
Jacob Lee,

7

To nie jest odpowiedź na twoje pytanie, ale tylko w tej części:

[3] wymaga zarówno identyfikatora, jak i nazwy… posiadanie obu jest nieco zbędne

Najprawdopodobniej i tak będziesz musiał mieć idatrybut w każdym polu formularza, aby móc powiązać <label>z nim jego element, na przykład:

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

Jest to wymagane ze względu na dostępność (tj. Jeśli nie kojarzysz etykiet formularzy i kontrolek, dlaczego tak bardzo nienawidzisz niewidomych?).

Jest to trochę zbędne, chociaż mniej, gdy masz pola wyboru / przyciski opcji, gdzie kilka z nich może współdzielić plik name. Ostatecznie idi namesłużą do różnych celów, nawet jeśli oba mają często tę samą wartość.


5
Jeśli umieścisz dane wejściowe w etykiecie, nie potrzebujesz identyfikatora ani atrybutu for. <label> Foo: <input type = "text" name = "foo" </label>
kennebec

3
To prawda, chociaż ogranicza to, co możesz osiągnąć pod względem wyglądu i dotyku.
Paul D. Waite

2
@ kennebec - powinieneś zawsze używać id, jeśli chcesz, aby etykieta była powiązana z elementem. Starsze wersje IE (<8?) Nie wiązały elementów wewnątrz etykiety z etykietą, jeśli nie było pasujących atrybutów dla i id .
RobG,

Oprócz tego, co napisał @kennebec, używanie identyfikatorów tworzy globalne pliki JS i należy ich unikać.
mikemaccana

1
@mikemaccana: Widziałem już wcześniej, że powoduje to problemy. Myślę, że jeśli twoje identyfikatory są rozsądnie opisowe, a twój JavaScript ma rozsądną przestrzeń nazw, jest mało prawdopodobne, że spowoduje to problemy.
Paul D. Waite,

6

To jest trochę stare, ale chcę dodać coś, co moim zdaniem jest istotne.
(Chciałem skomentować jeden lub 2 wątki powyżej, ale wydaje mi się, że potrzebuję 50 reputacji, a w chwili, gdy to piszę, mam tylko 21 :))
Chcę tylko powiedzieć, że są chwile, w których znacznie lepiej jest uzyskać dostęp do elementy formularza według nazwy zamiast identyfikatora. Nie mówię o samej formie. Formularz, OK, możesz nadać mu identyfikator, a następnie uzyskać do niego dostęp. Ale jeśli masz przycisk opcji w formularzu, znacznie łatwiej jest użyć go jako pojedynczego obiektu (uzyskać i ustawić jego wartość) i możesz to zrobić tylko z nazwy, o ile wiem.

Przykład:

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

Możesz pobrać / ustawić zaznaczoną wartość przycisku radiowego R1 jako całości, używając
document.mainForm.R1.value
lub
document.getElementById ("mainForm"). R1.value
Więc jeśli chcesz mieć jednolity styl, możesz chcesz zawsze używać tej metody, niezależnie od typu elementu formularza. Mnie, jestem całkowicie wygodny w dostępie do przycisków radiowych według nazwy i pól tekstowych według identyfikatora.


Co działa document.forms.mainForm.R1.value, co jest rzeczywiście dobrym sposobem na uniknięcie używania brzydkiego i żmudnego pisaniadocument.getElementById()
Kai Carver

2

Będąc staromodnym, zawsze używałem składni „document.myform.myvar”, ale ostatnio okazało się, że w przeglądarce Chrome nie działa (OK w przeglądarce Firefox i IE). Była to strona Ajax (tj. Załadowana do właściwości innerHTML elementu div). Być może Chrome nie rozpoznał formularza jako elementu głównego dokumentu. Zamiast tego użyłem getElementById (bez odwoływania się do formularza) i zadziałało OK.


możesz po prostu wstawić .forms, więc document.forms.myform.myvar
Kai Carver

1

Aby dodać do wszystkiego, co już zostało powiedziane, możesz uzyskać dostęp do inputs za pomocą namelub, idnajlepiej, używając elementswłaściwości formularza Object, ponieważ bez tego możesz uzyskać właściwość formularza o nazwie „foo” zamiast elementu HTML. I według @Paul D. Waite, dobrze jest mieć zarówno imię, jak i identyfikator.

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>

Według MDN na HTMLFormElement.elements stronie

Elementy właściwości HTMLFormElement zwracają kod HTMLFormControlsCollection zawierający wszystkie kontrolki formularza zawarte w elemencie. Niezależnie można uzyskać tylko liczbę kontrolek formularza za pomocą właściwości length.

Dostęp do określonej kontrolki formularza w zwróconej kolekcji można uzyskać przy użyciu indeksu lub nazwy lub identyfikatora elementu .


1

namepole działa dobrze. Zawiera odniesienie do elements.

parent.children- Wyświetla wszystkie elementy z polem nazwy rodzica. parent.elements- Wymieni tylko form elementstakie jakinput-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>

Uwaga: .elementsaby działał, parentmusi być <form> tag. Natomiast .childrenbędzie działać na każdym HTML-element- takim jak <div>, <span>, etc.

Powodzenia...


0

Formularz 2 jest w porządku, a formularz 3 jest również zalecany.
Nadmiarowość między nazwą a identyfikatorem jest spowodowana koniecznością zachowania kompatybilności, w html 5 niektóre elementy (jak img, form, iframe i tym podobne) stracą atrybut "name" i od teraz zaleca się używanie tylko ich id do odwoływania się do nich na :)


Wygląda na to, że elementy wejściowe nigdy nie utracą atrybutu nazwy ze względu na sposób, w jaki są używane przez języki po stronie serwera. Pozostaje więc pytanie, jaka jest metoda zgodna ze standardami, jeśli masz ustawiony tylko atrybut nazwy?
seth

W przypadku rozwoju zgodnego ze standardami na początek nie byłoby tylko nazwy. Jeśli naprawdę NIE MOŻESZ mieć identyfikatora, sugerowałbym funkcję document.getElementByName ().
Wintermute

0

Aby uzupełnić inne odpowiedzi, document.myForm.foo to tak zwany poziom DOM 0, który jest sposobem implementowanym przez Netscape i dlatego nie jest tak naprawdę otwartym standardem, mimo że jest obsługiwany przez większość przeglądarek.


4
Dostęp do formularzy i kontrolek formularzy poprzez nazwę, identyfikator i indeks jest częścią standardu DOM 2 HTML dla kolekcji HTML .
RobG,

0

Sprawdź tę stronę: https://developer.mozilla.org/En/DOM/Document.getElementsByName

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

Musi to być „elementy” i musi zwracać tablicę, ponieważ więcej niż jeden element może mieć taką samą nazwę.


@robert, myślę teraz, że to może być dobre rozwiązanie, chociaż to prosto z dokumentacji mnie zdenerwowało: „Ta metoda może być wątpliwa w użyciu, biorąc pod uwagę powyższe zmiany między typami dokumentów i obecne niestandardowe zachowanie w tym przypadku metoda w XHTML. "
seth

Cześć. Która dokumentacja sugerowała przeciwko temu? Myślę, że jeśli używasz xhtml we wszystkich środowiskach DOM, w których pracujesz, powinno być OK. Które przeglądarki tego nie obsługują? Oto dokumentacja dla IE: msdn.microsoft.com/en-us/library/ms536438(VS.85).aspx Oprócz Mozilli powyżej, kto jeszcze może jej nie obsługiwać?
robert

0

Moja odpowiedź będzie się różnić w odniesieniu do konkretnego pytania. Jeśli chcę uzyskać konkretny dostęp do określonego elementu, użyję document.getElementById (). Przykładem jest obliczanie pełnego imienia i nazwiska osoby, ponieważ opiera się na wielu polach, ale jest to powtarzalna formuła.

Jeśli chcę uzyskać dostęp do elementu jako części struktury funkcjonalnej (formularza), użyję:

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

Tak to działa również z punktu widzenia biznesu. Zmiany w pętli idą w parze ze zmianami funkcjonalnymi w aplikacji i dlatego mają znaczenie. Stosuję go głównie do przyjaznej dla użytkownika walidacji i zapobiegania połączeniom sieciowym w celu sprawdzenia błędnych danych. Powtarzam stronę serwera walidacji (i dodaję do niej więcej), ale jeśli mogę pomóc po stronie klienta użytkownika, jest to korzystne dla wszystkich.

Do agregacji danych (np. Budowania wykresu kołowego na podstawie danych w formularzu) używam dokumentów konfiguracyjnych i niestandardowych obiektów Javascript. Następnie dokładne znaczenie pola jest ważne w odniesieniu do jego kontekstu i czy używam document.getElementById ().


0

Ponieważ przypadek [2] document.myForm.footo dialekt z Internet Exploere. Więc zamiast tego wolę document.forms.myForm.elements.foolub document.forms["myForm"].elements["foo"].


-1

Wolę tą

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

2
Witamy w SO, doceniamy Twój wkład. Zmień swoją odpowiedź i wyjaśnij, dlaczego i jak.
B - rian
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.