Praktik Terbaik: Mengakses elemen formulir dengan ID HTML atau atribut nama?


141

Seperti yang diketahui oleh setiap pengembang JavaScript berpengalaman, ada banyak (terlalu banyak) cara untuk melakukan hal yang sama. Misalnya, Anda memiliki bidang teks sebagai berikut:

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

Ada banyak cara untuk mengakses ini di JavaScript:

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

Metode [1] dan [3] didokumentasikan dengan baik di dokumentasi Mozilla Gecko, tetapi keduanya tidak ideal. [1] terlalu umum untuk digunakan dan [3] membutuhkan id dan nama (dengan asumsi Anda akan memposting data ke bahasa sisi server). Idealnya, akan lebih baik jika hanya memiliki atribut id atau atribut nama (memiliki keduanya agak berlebihan, terutama jika id tidak diperlukan untuk css apa pun, dan meningkatkan kemungkinan salah ketik, dll).

[2] tampaknya yang paling intuitif dan tampaknya digunakan secara luas, tetapi saya belum melihatnya direferensikan dalam dokumentasi Gecko dan saya khawatir tentang kompatibilitas ke depan dan kompatibilitas lintas browser (dan tentu saja saya ingin menjadi sesuai standar mungkin).

Jadi apa praktik terbaik di sini? Adakah yang bisa menunjukkan sesuatu dalam dokumentasi DOM atau spesifikasi W3C yang dapat menyelesaikan masalah ini?

Catatan Saya secara khusus tertarik pada solusi non-perpustakaan (jQuery / Prototype).


Saya rasa intinya adalah saya mencari cara yang paling sesuai standar untuk mengakses elemen formulir menggunakan atribut name ...
seth

5
"memiliki keduanya agak berlebihan, terutama jika id tidak diperlukan untuk css apa pun, dan meningkatkan kemungkinan kesalahan ketik" - ID diperlukan untuk penggunaan label yang efektif. Bukan hanya CSS.

Terkadang ada beberapa formulir di halaman web dan atribut id dapat bertabrakan.
Calmarius

Jawaban:


99

Berikan formulir Anda hanya dengan id , dan masukkan nama saja:

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

Maka cara yang paling sesuai standar dan paling tidak bermasalah untuk mengakses elemen input Anda adalah melalui:

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

menggunakan .elements["foo"]alih-alih hanya .foolebih disukai karena yang terakhir mungkin mengembalikan properti bentuk bernama "foo" daripada elemen HTML!


1
@Karl ... Apa yang ingin Anda capai? Selain fakta bahwa menyebariskan JS ke dalam HTML Anda agak tidak elegan (dan seringkali tidak efisien, karena ini membuat fungsi pembungkus di sekitar kode), fakta bahwa Anda selalu mengembalikan false berarti formulir Anda tidak akan pernah terkirim. Jadi, kecuali jika formulir tidak dimaksudkan untuk dikirim (mungkin digunakan sepenuhnya oleh kode JS), atau kecuali myFunc (this) mengirimkannya melalui AJAX (dan Anda tidak peduli untuk melakukan pengiriman reguler sebagai cadangan jika AJAX gagal entah bagaimana), ... maka Anda telah melakukan kesalahan.
Lakukan

1
Biasanya, untuk mengirimkan hanya data formulir yang valid, Anda akan melakukan: myform.onsubmit = validateForm;(di mana myform adalah variabel yang mereferensikan elemen formulir, dan validateForm adalah nama fungsi validasi Anda ... tetapi Anda dapat menamainya myFunc jika Anda benar - benar ingin ). Poin pentingnya adalah bahwa validateForm()harus mengembalikan false setiap kali formulir tidak valid, serta menunjukkan bidang masalah kepada pengguna. Ini harus mengembalikan nilai true ketika data formulir divalidasi dengan benar, yang akan memungkinkan tindakan pengiriman untuk melanjutkan.
Lakukan

2
Ada alasan lain untuk menghindari id di bidang formulir: jika Anda menginginkan beberapa contoh dari formulir yang sama (di halaman yang sama).
koriander

1
@ João yang berfungsi juga, asalkan "foo" valid sebagai nama properti javascript. (Mungkin tidak - HTML5 hampir tidak membatasi nilai nameatribut, jadi misalnya Anda dapat memiliki <select name="a+b">atau <input type="text" name="...2">, yang tidak dapat direferensikan menggunakan javascript .propertyName notation). Notasi [] eksplisit juga memungkinkan nama dibangun dari ekspresi, misalnya myCheckBox = document.getElementById("myform").elements["CHK"+i]. Plus, secara gaya, menurut saya [] lebih baik- ini memperjelas bahwa ini bukan hanya properti dari objek javascript. YMMV.
Lakukan

1
Terkait linting, perlu diingat bahwa linting adalah panduan gaya saja, dan "error" linting tidak berarti javascript Anda tidak valid atau salah. Namun, dalam kasus khusus ini, yang dikatakan aturan linting adalah "lebih suka notasi titik saat mereferensikan properti objek javascript". Itu ide yang bagus, dan saya merekomendasikannya secara umum. TAPI sementara linter tidak menyadari hal ini, elementsbukan objek JS normal, dan elements.fooatau elements["foo"]sebenarnya sedang dikonversi ke elements.namedItem ("foo"). yaitu Anda memanggil fungsi yang ditentukan DOM , bukan mereferensikan properti JS!
Lakukan

36

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

" No-omg-never! " Muncul di benak saya ketika saya melihat metode akses elemen ini. Masalahnya adalah bahwa DOM mengasumsikan bahwa DOM adalah struktur data normal (misalnya: array) di mana urutan elemennya statis, konsisten, atau dapat diandalkan. Kami tahu bahwa 99,9999% dari waktu, bahwa ini bukanlah masalahnya. Penyusunan ulang atau inputelemen dalam formulir, menambahkan yang lain formke halaman sebelum formulir yang dipermasalahkan, atau memindahkan formulir yang dipermasalahkan adalah semua kasus di mana kode ini rusak. Cerita pendek: ini sangat rapuh. Begitu Anda menambah atau memindahkan sesuatu, itu akan rusak.

[2] document.myForm.foo;

Saya bersama Sergey ILinsky dalam hal ini:

  • Akses elemen arbitrer dengan mengacu pada idatributnya:document.getElementById("myform");
  • Akses elemen formulir bernama menurut nama, relatif terhadap elemen formulir induknya: document.getElementById("myform").foo;

Masalah utama saya dengan metode ini adalah nameatribut tidak berguna saat diterapkan ke formulir. Nama tidak diteruskan ke server sebagai bagian dari POST / GET dan tidak berfungsi untuk penanda gaya hash.

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

Menurut pendapat saya, ini adalah metode yang paling disukai. Akses langsung adalah metode yang paling ringkas dan jelas.

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

Menurut pendapat saya, ini bisa diterima, tetapi lebih bertele-tele dari yang diperlukan. Metode # 3 lebih disukai.


Saya kebetulan menonton video dari Douglas Crockford dan dia membahas tentang subjek ini. Tempat tujuan berada di -12: 00. Untuk meringkas:

  • Koleksi dokumen (document.anchor, document.form, dll) sudah usang dan tidak relevan (metode 1).
  • The nameatribut digunakan untuk nama hal-hal, tidak untuk mengaksesnya. Ini untuk menamai hal-hal seperti windows, kolom input, dan tag jangkar.
  • "ID adalah hal yang harus Anda gunakan untuk mengidentifikasi elemen secara unik sehingga Anda bisa mendapatkan akses ke sana. Mereka (nama dan ID) dulunya dapat dipertukarkan, tetapi sekarang tidak lagi."

Jadi begitulah. Secara semantik, ini paling masuk akal.


2
Jadi apakah ini hanya peretasan? document.getElementById ("myform"). foo; Setelah mempelajari DOM cukup banyak, saya tidak jelas mengapa ini berhasil. Dugaan saya adalah objek formulir juga merupakan larik elemen anaknya yang diindeks pada atribut nama html ...
seth

1
Anda juga menyebutkan "nama tidak dikirimkan ke server sebagai bagian dari POST / GET dan tidak berfungsi untuk penanda gaya hash". Bukankah ini tepatnya yang dikirimkan ke server? Saat Anda bekerja dengan PHP, atribut name itulah yang menjadi indeks Anda di $ _POST global.
seth

2
@Justin, itu adalah atribut nama yang diteruskan ke server.
Anurag

2
@seth Spesifikasi DOM yang lebih lama tampak sangat tidak jelas tentang mengapa document.aForm.fooberfungsi, tetapi spesifikasi HTML5 tampaknya dengan jelas mendefinisikan antarmuka HTMLFormElementyang memilikinya caller getter any namedItem(in DOMString name);. Lebih lanjut di whatwg.org/specs/web-apps/current-work/multipage/…
Anurag

1
@ kalian berdua: "... atribut nama tidak berguna ketika diterapkan ke formulir ..." Saya tidak berbicara tentang atribut nama dari inputatau select, saya berbicara tentang atribut nama dari a form. Atribut nama a form tidak diteruskan ke server.
Justin Johnson

14

Untuk mengakses elemen bernama yang ditempatkan di formulir, praktik yang baik adalah menggunakan formobjek itu sendiri.

Untuk mengakses elemen arbitrer di pohon DOM yang terkadang dapat ditemukan dalam formulir, gunakan getElementByIddan elemen id.


8
Apa maksudmu "gunakan objek bentuk itu sendiri"? Setelah Anda memiliki objek formulir, metode apa yang Anda gunakan untuk mengakses elemen tertentu?
seth

2
Maksud saya, saya akan merekomendasikan penggunaan N5 (document.getElementById ('myForm'). Elements.foo) untuk mengakses item bernama dan N6 (document.getElementById ('myForm'). Elemen) untuk mengakses koleksi elemen yang dapat diulang
Sergey Ilinsky

Saya mendefinisikan gaya kode saya ... dan sebagai preferensi, saya tetap menggunakan ID .... dengan cara itu akses elemen konsisten di seluruh halaman. + alasan lain yang disebutkan.

1
Mengapa praktik yang baik untuk mengakses formulir menggunakan getElementID? mengapa document.myForm tidak berfungsi? (Saya memiliki situasi di mana ini tidak berfungsi dan saya bertanya-tanya mengapa)
Spundun

Halo Spundun, Anda mungkin telah memecahkan masalah Anda beberapa bulan yang lalu (atau mungkin Anda angkat tangan :)), tetapi jika Anda bertanya-tanya, itu mungkin karena Anda tidak memberikan elemen HTML formulir Anda dengan atribut "nama".
Sheldon R.

8

Saya lebih suka metode ke-5. Yaitu
[5] Gunakan pengenal JavaScript khusus ini untuk meneruskan objek formulir atau bidang ke fungsi dari event handler.

Khususnya, untuk formulir:

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

dan

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

Dengan menggunakan teknik ini, fungsi tidak perlu tahu
- urutan di mana formulir didefinisikan di halaman,
- ID formulir, atau
- nama formulir

Demikian pula untuk bidang:

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

dan

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

Dalam kasus ini, fungsi tidak perlu mengetahui nama atau id dari bidang bobot tertentu, meskipun perlu mengetahui nama bidang batas bobot.


Tidak yakin apa penyebab dasarnya, tetapi saya telah melakukan pendekatan ini mengembalikan string kosong dalam beberapa, tetapi tidak semua, keadaan.
Jacob Lee

7

Ini tidak benar-benar menjawab pertanyaan Anda, tetapi hanya pada bagian ini:

[3] membutuhkan baik id dan nama ... memiliki keduanya agak berlebihan

Anda kemungkinan besar harus memiliki idatribut pada setiap bidang formulir, sehingga Anda dapat mengaitkan <label>elemennya dengannya, seperti ini:

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

Ini diperlukan untuk aksesibilitas (misalnya jika Anda tidak mengaitkan label dan kontrol formulir, mengapa Anda begitu membenci orang buta?).

Ini agak mubazir, meskipun kurang begitu bila Anda memiliki kotak centang / tombol radio, di mana beberapa di antaranya dapat berbagi file name. Pada akhirnya, iddan nameuntuk tujuan yang berbeda, meskipun keduanya sering kali disetel ke nilai yang sama.


5
Jika Anda memasukkan input ke dalam labelnya, Anda tidak memerlukan id atau atribut for. <label> Foo: <input type = "text" name = "foo" </label>
kennebec

3
Sangat benar, meskipun itu membatasi apa yang dapat Anda capai dalam hal tampilan dan nuansa.
Paul D. Waite

2
@ kennebec — Anda harus selalu menggunakan id jika Anda ingin label dikaitkan dengan elemen. Versi IE yang lebih lama (<8?) Tidak mengasosiasikan elemen di dalam label dengan label jika tidak ada atribut yang cocok untuk dan id .
RobG

Selain apa yang ditulis @kennebec, menggunakan ID menciptakan JS global dan harus dihindari.
mikemaccana

1
@ Mikemaccana: Saya telah melihat penyebab masalah itu sebelumnya. Saya pikir jika ID Anda cukup deskriptif dan JavaScript Anda diberi spasi dengan tepat, itu tidak mungkin menyebabkan masalah.
Paul D. Waite

6

Ini agak tua tapi saya ingin menambahkan sesuatu yang menurut saya relevan.
(Saya bermaksud untuk mengomentari satu atau 2 utas di atas tetapi tampaknya saya memerlukan reputasi 50 dan saya hanya memiliki 21 pada saat menulis ini. :))
Hanya ingin mengatakan bahwa ada kalanya jauh lebih baik untuk mengakses elemen formulir berdasarkan nama, bukan dengan id. Saya tidak berbicara tentang formulir itu sendiri. Bentuknya, OK, Anda bisa memberinya id dan kemudian mengaksesnya dengan itu. Tetapi jika Anda memiliki tombol radio dalam formulir, jauh lebih mudah menggunakannya sebagai objek tunggal (mendapatkan dan menyetel nilainya) dan Anda hanya dapat melakukannya dengan nama, sejauh yang saya tahu.

Contoh:

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

Anda bisa mendapatkan / menyetel nilai yang dicentang dari tombol radio R1 secara keseluruhan dengan menggunakan
document.mainForm.R1.value
atau
document.getElementById ("mainForm"). R1.value
Jadi jika Anda ingin memiliki gaya kesatuan, Anda mungkin ingin selalu menggunakan metode ini, apa pun jenis elemen formulirnya. Saya, saya sangat nyaman mengakses tombol radio dengan nama dan kotak teks dengan id.


Apa yang berhasil adalah document.forms.mainForm.R1.value, yang memang merupakan cara yang bagus untuk menghindari penggunaan tipe jelek dan membosankandocument.getElementById()
Kai Carver

2

Menjadi kuno, saya selalu menggunakan sintaks 'document.myform.myvar' tetapi baru-baru ini saya menemukannya gagal di Chrome (OK di Firefox dan IE). Itu adalah halaman Ajax (yaitu dimuat ke dalam properti innerHTML dari sebuah div). Mungkin Chrome tidak mengenali formulir sebagai elemen dokumen utama. Saya menggunakan getElementById (tanpa mereferensikan formulir) sebagai gantinya dan berfungsi dengan baik.


Anda bisa memasukkannya .forms, jadi document.forms.myform.myvar
Kai Carver

1

Hanya untuk menambahkan semua yang telah dikatakan, Anda dapat mengakses input s baik dengan nameatau idmenggunakan elementsproperti dari formulir Objek, karena tanpanya Anda bisa mendapatkan properti dari formulir bernama "foo" daripada elemen HTML. Dan menurut @Paul D. Waite tidak masalah untuk memiliki nama dan 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>

Menurut MDN di halaman HTMLFormElement.elements

Elemen properti HTMLFormElement mengembalikan HTMLFormControlsCollection yang mencantumkan semua kontrol formulir yang terdapat dalam elemen. Secara independen, Anda hanya dapat memperoleh jumlah kontrol formulir menggunakan properti panjang.

Anda dapat mengakses kontrol bentuk tertentu dalam koleksi dikembalikan oleh baik menggunakan indeks atau elemen nama atau id .


1

namelapangan bekerja dengan baik. Ini memberikan referensi keelements .

parent.children- Akan mencantumkan semua elemen dengan bidang nama induk. parent.elements- Akan daftar hanya form elementssepertiinput-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>

Catatan: Untuk .elementsbekerja, parentkebutuhannya adalah a <form> tag. Padahal, .childrenakan bekerja pada apa HTML-element- seperti<div>, <span>, etc .

Semoga berhasil...


0

Formulir 2 tidak masalah, dan formulir 3 juga direkomendasikan.
Redundansi antara nama dan id disebabkan oleh kebutuhan untuk menjaga kompatibilitas, pada html 5 beberapa elemen (seperti img, form, iframe dan semacamnya) akan kehilangan atribut "name" -nya, dan disarankan untuk hanya menggunakan id mereka untuk mereferensikannya mulai sekarang di :)


Tampaknya elemen input tidak akan pernah kehilangan atribut namanya karena cara penggunaannya oleh bahasa sisi server. Jadi pertanyaannya tetap, apa metode yang memenuhi standar jika Anda hanya menyetel atribut name?
seth

Dalam pengembangan yang sesuai standar, Anda tidak akan hanya memiliki nama, sebagai permulaan. Jika Anda benar-benar TIDAK BISA memiliki ID, maka saya sarankan fungsi document.getElementByName ().
Wintermute

0

Untuk melengkapi jawaban lainnya, document.myForm.foo adalah yang disebut DOM level 0, yang merupakan cara yang diterapkan oleh Netscape dan oleh karena itu sebenarnya bukan standar terbuka meskipun didukung oleh sebagian besar browser.


4
Mengakses formulir dan kontrol formulir berdasarkan nama, id, dan indeks adalah bagian dari standar HTML DOM 2 untuk koleksi HTML .
RobG

0

Lihat halaman ini: https://developer.mozilla.org/En/DOM/Document.getElementsByName

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

Ini harus berupa 'elemen' dan harus mengembalikan array karena lebih dari satu elemen dapat memiliki nama yang sama.


@robert, saya sekarang berpikir ini mungkin solusi yang baik, meskipun ini langsung dari dokumen membuat saya gugup: "Metode ini mungkin dipertanyakan untuk digunakan mengingat perubahan di atas antara jenis dokumen dan perilaku non-standar saat ini untuk ini metode dalam XHTML. "
seth

Halo. Dokumentasi mana yang menentang hal ini? Saya pikir jika Anda menggunakan xhtml di semua lingkungan DOM tempat Anda bekerja, maka Anda akan baik-baik saja. Selain itu, browser mana yang tidak mendukung ini? Berikut adalah dokumen untuk IE: msdn.microsoft.com/en-us/library/ms536438(VS.85).aspx Selain Mozilla di atas, siapa lagi yang mungkin tidak mendukungnya?
robert

0

Jawaban saya akan berbeda pada pertanyaan pastinya. Jika saya ingin mengakses elemen tertentu secara khusus, maka saya akan menggunakan document.getElementById (). Contohnya adalah menghitung nama lengkap seseorang, karena ia membangun di beberapa bidang, tetapi ini adalah rumus yang dapat diulang.

Jika saya ingin mengakses elemen sebagai bagian dari struktur fungsional (formulir), maka saya akan menggunakan:

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

Beginilah cara kerjanya dari perspektif bisnis. Perubahan di dalam loop mengikuti perubahan fungsional dalam aplikasi dan karenanya berarti. Saya menerapkannya sebagian besar untuk validasi yang ramah pengguna dan mencegah panggilan jaringan untuk memeriksa data yang salah. Saya ulangi sisi server validasi (dan menambahkannya di sana lagi), tetapi jika saya dapat membantu sisi klien pengguna, apakah itu bermanfaat bagi semua.

Untuk agregasi data (seperti membuat diagram lingkaran berdasarkan data di formulir) saya menggunakan dokumen konfigurasi dan objek Javascript yang dibuat khusus. Lalu adalah arti sebenarnya dari bidang yang penting dalam kaitannya dengan konteksnya dan apakah saya menggunakan document.getElementById ().


0

Saya lebih suka Yang Ini

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

2
Selamat datang di SO, kami menghargai masukan Anda. Harap edit jawaban Anda dan jelaskan mengapa dan bagaimana.
B - rian

0

Karena case [2] document.myForm.fooadalah dialek dari Internet Exploere. Jadi daripada itu, saya lebih suka document.forms.myForm.elements.fooatau document.forms["myForm"].elements["foo"].

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.