Bagaimana cara tombol kirim default pada formulir HTML ditentukan?

210

Jika suatu formulir dikirimkan tetapi tidak dengan tombol tertentu, seperti

  • dengan menekan Enter
  • gunakan HTMLFormElement.submit()di JS

Bagaimana cara browser menentukan tombol pengiriman mana yang harus digunakan, seperti yang ditekan?

Ini signifikan pada dua tingkatan:

  • memanggil onclickpengendali acara yang dilampirkan pada tombol kirim
  • data dikirim kembali ke server web

Eksperimen saya sejauh ini menunjukkan bahwa:

  • saat menekan Enter, Firefox, Opera dan Safari menggunakan tombol kirim pertama dalam formulir
  • saat menekan Enter, IE menggunakan tombol kirim pertama atau tidak sama sekali tergantung pada kondisi yang saya belum bisa mengetahuinya
  • semua browser ini tidak menggunakan sama sekali untuk pengiriman JS

Apa yang dikatakan standar?

Jika itu akan membantu, ini kode pengujian saya (PHP hanya relevan untuk metode pengujian saya, bukan untuk pertanyaan saya sendiri)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Test</title>
</head>

<body>

<h1>Get</h1>
<dl>
<?php foreach ($_GET as $k => $v) echo "<dt>$k</dt><dd>$v</dd>"; ?>
</dl>

<h1>Post</h1>
<dl>
<?php foreach ($_POST as $k => $v) echo "<dt>$k</dt><dd>$v</dd>"; ?>
</dl>

<form name="theForm" method="<?php echo isset($_GET['method']) ? $_GET['method'] : 'get'; ?>" action="<?php echo $_SERVER['SCRIPT_NAME']; ?>">
    <input type="text" name="method" />
    <input type="submit" name="action" value="Button 1" onclick="alert('Button 1'); return true" />
    <input type="text" name="stuff" />
    <input type="submit" name="action" value="Button 2" onclick="alert('Button 2'); return true" />
    <input type="button" value="submit" onclick="document.theForm.submit();" />
</form>

</body></html>
Stewart
sumber

Jawaban:

115

Jika Anda mengirimkan formulir melalui Javascript (yaitu formElement.submit()setara atau apa pun), maka tidak ada tombol kirim yang dianggap berhasil dan tidak ada nilainya yang dimasukkan dalam data yang dikirimkan. (Perhatikan bahwa jika Anda mengirimkan formulir dengan menggunakan, submitElement.click()maka kiriman yang Anda rujuk dianggap aktif; ini tidak benar-benar termasuk dalam pengajuan pertanyaan Anda karena di sini tombol kirim tidak ambigu tetapi saya pikir saya akan memasukkannya bagi orang-orang yang membaca bagian pertama dan bertanya-tanya bagaimana membuat tombol kirim berhasil melalui pengiriman formulir JS. Tentu saja, pengurus onsub bentuk formulir masih akan menembak dengan cara ini sedangkan mereka tidak akan melalui form.submit()sehingga ketel ikan lain ...)

Jika formulir dikirimkan dengan menekan Enter ketika berada di bidang non-textarea, maka itu sebenarnya tergantung pada agen pengguna untuk memutuskan apa yang diinginkan di sini. The spesifikasi tidak mengatakan apa-apa tentang mengirimkan formulir dengan menggunakan masukkan sementara kunci dalam bidang entri teks (jika Anda tab untuk tombol dan mengaktifkannya menggunakan ruang atau apa pun, maka tidak ada masalah spesifik yang tombol submit jelas digunakan). Semua itu mengatakan bahwa suatu formulir harus diserahkan ketika tombol kirim diaktifkan, itu bahkan bukan persyaratan bahwa menekan masuk misalnya input teks akan mengirimkan formulir.

Saya percaya bahwa Internet Explorer memilih tombol kirim yang muncul pertama kali di sumber; Saya punya firasat bahwa Firefox dan Opera memilih tombol dengan tabindex terendah, kembali ke yang pertama jika tidak ada yang didefinisikan. Ada juga beberapa komplikasi mengenai apakah kiriman memiliki atribut nilai non-default IIRC.

Maksudnya adalah tidak ada standar yang ditentukan untuk apa yang terjadi di sini dan sepenuhnya bergantung pada browser - sejauh mungkin dalam apa pun yang Anda lakukan, cobalah untuk tidak mengandalkan perilaku tertentu. Jika Anda benar-benar harus tahu, Anda mungkin bisa mengetahui perilaku berbagai versi browser tetapi ketika saya menyelidiki ini beberapa waktu lalu ada beberapa kondisi yang cukup berbelit-belit (yang tentu saja dapat berubah dengan versi browser baru) dan saya akan menyarankan Anda menghindarinya jika memungkinkan!

Andrzej Doyle
sumber
1
Re para 2: Pertanyaan dasar saya adalah apakah ada sesuatu dalam spesifikasi apa pun untuk efek "Jika browser menyediakan cara mengirimkan formulir tanpa menentukan kontrol pengiriman ...". Tetapi saya menjawab dari jawaban David bahwa tidak ada. Maksud saya tentang IE adalah bahwa kadang-kadang menekan Enter mengirimkan formulir dan tidak mengatur tombol kirim. Konsekuensinya adalah, jika Anda memiliki beberapa formulir yang mengirimkan ke skrip yang sama, Anda tidak dapat mengandalkan tombol kirim untuk membedakannya. Ini muncul dalam proyek yang sedang saya kerjakan.
Stewart
1
Bagian braket paragraf pertama yang sangat berguna - terima kasih.
rbassett
63

HTML 4 tidak membuatnya eksplisit. Draf kerja HTML5 saat ini menetapkan bahwa tombol kirim pertama harus default :

Sebuah formtombol standar elemen adalah yang pertama tombol submit di urutan pohon yang pemilik bentuk adalah bahwa formelemen.

Jika agen pengguna mendukung membiarkan pengguna mengirimkan formulir secara implisit (misalnya, pada beberapa platform menekan tombol "enter" saat bidang teks difokuskan secara implisit mengirimkan formulir), maka melakukannya untuk formulir yang tombol default-nya memiliki aktivasi yang ditentukan perilaku harus menyebabkan agen pengguna menjalankan langkah-langkah aktivasi klik sintetis pada tombol default itu .

Quentin
sumber
Ok, jadi itu yang seharusnya dilakukan. Bisakah saya menggunakan?
Pacerier
Saya senang melihat "pengiriman tersirat" dalam HTML5.
Clint Pachl
61

Andrezj sudah cukup berhasil mengatasinya ... tapi ini solusi lintas-browser yang mudah.

Ambil bentuk seperti ini:

<form>
    <input/>
    <button type="submit" value="some non-default action"/>
    <button type="submit" value="another non-default action"/>
    <button type="submit" value="yet another non-default action"/>

    <button type="submit" value="default action"/>
</form>

dan refactor untuk ini:

<form>
    <input/>

    <button style="overflow: visible !important; height: 0 !important; width: 0 !important; margin: 0 !important; border: 0 !important; padding: 0 !important; display: block !important;" type="submit" value="default action"/>

    <button type="submit" value="some non-default action"/>
    <button type="submit" value="another non-default action"/>
    <button type="submit" value="yet another non-default action"/>
    <button type="submit" value="still another non-default action"/>

    <button type="submit" value="default action"/>
</form>

Karena spesifikasi W3C menunjukkan beberapa tombol kirim valid, tetapi mengabaikan panduan tentang bagaimana agen pengguna harus menanganinya, produsen browser dibiarkan menerapkan sebagaimana yang mereka inginkan. Saya menemukan mereka akan mengirim tombol kirim pertama dalam formulir, atau mengirim tombol kirim berikutnya setelah bidang formulir yang saat ini memiliki fokus.

Sayangnya, cukup menambahkan gaya tampilan: tidak ada; tidak akan berfungsi karena spesifikasi W3C menunjukkan elemen tersembunyi apa pun harus dikecualikan dari interaksi pengguna. Jadi sembunyikan saja di depan mata!

Di atas adalah contoh dari solusi yang akhirnya saya produksi. Menekan tombol enter memicu pengiriman formulir default adalah perilaku seperti yang diharapkan, bahkan ketika nilai-nilai non-standar lain hadir dan mendahului tombol pengiriman default di DOM. Bonus untuk interaksi mouse / keyboard dengan input pengguna eksplisit sambil menghindari penangan javascript.

Catatan: menabrak formulir tidak akan menampilkan fokus untuk elemen visual apa pun namun masih akan menyebabkan tombol yang tidak terlihat dipilih. Untuk menghindari masalah ini, cukup atur atribut tabindex sesuai dan hilangkan atribut tabindex pada tombol kirim tak terlihat. Meskipun tampaknya tidak sesuai untuk mempromosikan gaya ini ke! Penting, mereka harus mencegah kerangka kerja atau gaya tombol yang ada dari mengganggu perbaikan ini. Juga, gaya inline itu jelas merupakan bentuk yang buruk, tapi kami membuktikan konsep di sini ... bukan menulis kode produksi.

James
sumber
5
Terima kasih. Tersandung di layar: tidak ada masalah juga. Alih-alih meminimalkan tombol, Anda juga dapat memindahkannya dari halaman dengan menghapusnya dengan a <div style="position: fixed; left: -1000px; top: -1000px />. Hanya satu hal lagi yang perlu diperhatikan: Hanya meminimalkan atau memindahkan tombol dari aliran halaman dengan CSS mungkin memunculkan masalah WAI, karena pembaca layar masih akan melihat tombol default.
Stefan Haberl
2
Terima kasih @James atas jawaban terperinci ini.
Nathan
1
ini berhasil untuk saya, terima kasih. Saya harus menambahkan ini untuk perbatasan tombol: tidak ada; untuk membuatnya menghilang dengan
terhormat
4
Anda cukup mengatur atribut tabindex dari tombol tersembunyi ke -1
tvanc
2
Untuk apa itu <input/>di sana?
Sz.
16

Saya pikir posting ini akan membantu jika seseorang ingin melakukannya dengan jQuery:

http://greatwebguy.com/programming/dom/default-html-button-submit-on-enter-with-jquery/

Solusi dasarnya adalah:

$(function() {
    $("form input").keypress(function (e) {
    if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
        $('input[type=submit].default').click();
        return false;
    } else {
        return true;
    }
    });
});

dan satu lagi yang saya suka adalah:

jQuery(document).ready(function() {
$("form input, form select").live('keypress', function (e) {
if ($(this).parents('form').find('button[type=submit].default, input[type=submit].default').length <= 0)
return true;

if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
$(this).parents('form').find('button[type=submit].default, input[type=submit].default').click();
return false;
} else {
return true;
}
});
}); 
Rodrigo Caballero
sumber
jQuery.Event selalu memiliki .wichatributnya. Juga tidak perlu kembali ke DOM .keyCode(atau .charCodedalam hal ini).
Arjan
Masalah lain tentang jQuery di sini adalah permintaan ganda yang tidak perlu. Karena tidak perlu mengembalikan true, selain itu, versi jQuery menjadi sangat jelas dan pendek dalam mengintegrasikan pengurangan yang disarankan oleh Arjan sebelumnya.
soletan
Saya menggunakan keydown alih-alih menekan tombol (menghindari menunggu keyup) dan saya menambahkan e.preventDefault();ke awal fungsi ini untuk menghindari eksekusi tombol default "nyata". Bekerja dengan sangat baik.
Matt Roy
6

Saya memiliki formulir dengan 11 tombol kirim, dan akan selalu menggunakan tombol kirim pertama saat pengguna menekan enter. Saya membaca di tempat lain bahwa itu bukan ide yang baik (praktik buruk) untuk memiliki lebih dari satu tombol kirim pada formulir, dan cara terbaik untuk melakukan ini adalah memiliki tombol yang Anda inginkan sebagai default, karena satu-satunya tombol kirim pada formulir. Tombol-tombol lain harus dibuat menjadi "TYPE = BUTTON" dan acara onClick menambahkan bahwa panggilan Anda sendiri mengirimkan rutin dalam Javascript. Sesuatu seperti ini :-

<SCRIPT Language="JavaScript">
function validform()
{
  // do whatever you need to validate the form, and return true or false accordingly
}

function mjsubmit()
{
  if (validform()) { document.form1.submit(); return true;}
  return false;
}
</SCRIPT>
<INPUT TYPE=BUTTON NAME="button1" VALUE="button1" onClick="document.form1.submitvalue='button1'; return mjsubmit();">
<INPUT TYPE=BUTTON NAME="button2" VALUE="button2" onClick="document.form1.submitvalue='button2'; return mjsubmit();">
<INPUT TYPE=SUBMIT NAME="button3" VALUE="button3" onClick="document.form1.submitvalue='button3'; return validform();">
<INPUT TYPE=BUTTON NAME="button4" VALUE="button4" onClick="document.form1.submitvalue='button4'; return mjsubmit();">

Di sini, tombol3 adalah default, dan meskipun Anda secara pemrograman mengirimkan formulir dengan tombol lain, rutinitas mjsubmit memvalidasinya. HTH.

grafis
sumber
19
Ide buruk. Formulir Anda tidak akan berfungsi jika JS dinonaktifkan. JS harus digunakan secara tidak mencolok.
BalusC
7
Sangat sedikit browser yang JS dinonaktifkan secara default, bahkan yang ada di iPod! Pada formulir yang saya kutip, JS off akan membuatnya tidak berguna! Begitu banyak bergantung pada JS running.
grafik
7
Dimatikan secara default atau tidak, mereka yang menonaktifkan JS seharusnya tidak perlu menyalakannya hanya untuk menghindari hambatan kecil konyol seperti ini.
Stewart
2
apa bentuk memiliki 11 tombol kirim ?? ( rasa ingin tahu )
Ben
2
Alasan terbesar yang saya lihat memvalidasi Javascript tidak mencolok adalah bahwa Javascript menonjol cenderung fiddly. Saya tidak yakin bagaimana memenuhi syarat apa yang saya pikirkan, tetapi ketika saya melihat halaman yang benar-benar bergantung pada JS, saya juga bertaruh saya dapat melakukan beberapa hal rumit dengan DOM saya dan melakukan sesuatu yang tidak diinginkan pada server.
Samantha Branham
6

Ini sekarang dapat diselesaikan menggunakan flexbox:

HTML

<form>
    <h1>My Form</h1>
    <label for="text">Input:</label>
    <input type="text" name="text" id="text"/>

    <!-- Put the elements in reverse order -->
    <div class="form-actions">
        <button>Ok</button> <!-- our default action is first -->
        <button>Cancel</button>
    </div>
</form>

CSS

.form-actions {
    display: flex;
    flex-direction: row-reverse; /* reverse the elements inside */
}

Penjelasan
Menggunakan kotak flex, kita dapat membalik urutan unsur-unsur dalam sebuah wadah yang menggunakan display: flexdengan juga menggunakan aturan CSS: flex-direction: row-reverse. Ini tidak memerlukan CSS atau elemen tersembunyi. Untuk browser lama yang tidak mendukung flexbox, mereka masih mendapatkan solusi yang bisa diterapkan tetapi elemen tidak akan terbalik.

Demo
http://codepen.io/Godwin/pen/rLVKjm

Godwin
sumber
2

Saya kesulitan dengan pertanyaan yang sama karena saya telah mengirimkan tombol di tengah dari mana pengalihan dikirim ke halaman lain, seperti:

<button type="submit" onclick="this.form.action = '#another_page'">More</button>

Ketika pengguna menekan tombol enter, tombol ini diklik alih-alih tombol kirim lainnya.

Jadi saya melakukan beberapa tes primitif dengan membuat dari dengan beberapa tombol kirim dan opsi visibilitas yang berbeda dan onclick event yang memberitahukan tombol mana yang diklik: https://jsfiddle.net/aqfy51om/1/

Browser dan OS yang saya gunakan untuk pengujian:

WINDOWS

  • Google Chrome 43 (ayolah google: D)
  • Mozilla Firefox 38
  • Internet Explorer 11
  • Opera 30.0

OSX

  • Google Chrome 43
  • Safari 7.1.6

Sebagian besar browser ini mengklik tombol pertama meskipun opsi visibilitas diterapkan kecuali IE dan Safari yang mengklik tombol ketiga, yang "terlihat" di dalam wadah "tersembunyi":

<div style="width: 0; height: 0; overflow: hidden;">
    <button type="submit" class="btn btn-default" onclick="alert('Hidden submit button #3 was clicked');">Hidden submit button #3</button>
</div>

Jadi saran saya, yang akan saya gunakan sendiri, adalah:

Jika formulir Anda memiliki beberapa tombol kirim dengan makna berbeda, maka sertakan tombol kirim dengan tindakan default di awal formulir, yaitu:

  1. Sepenuhnya terlihat
  2. Dibungkus dengan wadah style="width: 0; height: 0; overflow: hidden;"

EDIT Pilihan lain mungkin untuk mengimbangi tombol (masih di awal dari) style="position: absolute; left: -9999px; top: -9999px;", hanya mencobanya di IE - bekerja, tetapi saya tidak tahu apa lagi yang bisa gagal, misalnya mencetak ..

Kristian
sumber
1

Dari komentar Anda:

Konsekuensinya adalah, jika Anda memiliki beberapa formulir yang mengirimkan ke skrip yang sama, Anda tidak bisa mengandalkan tombol kirim untuk membedakannya.

Saya masukkan <input type="hidden" value="form_name" />ke dalam setiap formulir.

Jika mengirimkan dengan javascript: tambahkan ajukan acara ke formulir, jangan klik acara ke tombolnya. Pengguna Saavy tidak terlalu sering menyentuh mouse mereka.

Ryan Florence
sumber
Memang, tapi itu menimbulkan pertanyaan ini: stackoverflow.com/questions/541869/…
Stewart
1

Ketika Anda memiliki beberapa tombol kirim dalam satu formulir dan pengguna menekan tombol ENTER untuk mengirimkan formulir dari bidang teks, kode ini mengabaikan fungsi default, dengan memanggil acara kirim pada formulir dari acara tekan tombol. Ini kode itu:

$('form input').keypress(function(e){

    if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)){ $(e.target).closest('form').submit(); return false; }
    else return true;

});
aksioma82
sumber
Sederhana dan memperbaiki masalah
toddmo
1

Aneh bahwa tombol pertama Masukkan pergi selalu tombol pertama tanpa terlihat atau tidak, misalnya menggunakan jquery show/hide(). Menambahkan atribut .attr('disabled', 'disabled')mencegah sepenuhnya menerima tombol Enter submit. Masalahnya misalnya ketika menyesuaikan visibilitas Insert / Edit + Delete button dalam dialog rekaman. Saya menemukan lebih sedikit peretasan dan penempatan Edit di depan Sisipkan

<button type="submit" name="action" value="update">Update</button>
<button type="submit" name="action" value="insert">Insert</button>
<button type="submit" name="action" value="delete">Delete</button>

dan gunakan kode javascript:

$("#formId button[type='submit'][name='action'][value!='insert']").hide().attr('disabled', 'disabled');
$("#formId button[type='submit'][name='action'][value='insert']").show().removeAttr('disabled');
TMa
sumber
0

resep saya:

<form>
<input type=hidden name=action value=login><!-- the magic! -->

<input type=text name=email>
<input type=text name=password>

<input type=submit name=action value=login>
<input type=submit name=action value="forgot password">
</form>

Ini akan mengirimkan bidang tersembunyi default jika tidak ada tombol yang 'diklik'.

jika diklik, mereka memiliki preferensi dan nilainya dilewatkan.

gcb
sumber
2
Tetapi apakah perilaku ini ditentukan oleh standar? Dan bisakah browser dipercaya untuk mengimplementasikannya dengan benar?
Stewart
Pertanyaan bagus. Saya telah mengujinya untuk bekerja di semua browser A (dari matriks browser yui) dan ini adalah yang paling konsisten yang bisa saya dapatkan dalam kehidupan nyata (terlepas dari apa yang ditentukan oleh standar)
gcb
@yellowandred apa yang terjadi? akan kita lihat nanti
gcb
1
kesalahan saya, saya mengubah {type = "hidden"} dan saya tidak melihat nilai 'nama' yang sama.
Kuning dan Merah
Ini tidak berfungsi untuk saya di IE11 atau Fx30. Nilai selalu diatur ke nilai tersembunyi.
Jamie Kitson
0

Solusi lain yang saya gunakan adalah hanya memiliki satu tombol dalam formulir, dan memalsukan tombol lainnya.

Ini sebuah contoh:

<form>
  <label for="amount">Amount of items</label>
  <input id="amount" type="text" name="amount" />
  <span id="checkStock" class="buttonish">Check stock</span>
  <button type="submit" name="action" value="order">Place order</button>
</form>

Saya kemudian gaya elemen rentang agar terlihat seperti tombol. Seorang pendengar JS mengamati rentang dan melakukan operasi yang diinginkan setelah diklik.

Tidak selalu tepat untuk semua situasi, tetapi setidaknya itu cukup mudah dilakukan.

Johan Fredrik Varen
sumber
1
Apa fallback untuk pengguna yang menonaktifkan JS?
Stewart
Pengguna dengan JS yang dinonaktifkan tidak akan dapat menggunakan internet, sesederhana itu saat ini.
Christoffer Bubach
0

Dari spesifikasi HTML 4 :

Jika suatu formulir berisi lebih dari satu tombol kirim, hanya tombol kirim yang diaktifkan yang berhasil.

Ini berarti bahwa diberikan lebih dari 1 tombol kirim dan tidak ada yang diaktifkan (diklik), tidak ada yang harus berhasil.

Dan saya berpendapat ini masuk akal: Bayangkan formulir besar dengan banyak tombol kirim. Di bagian atas, ada tombol "hapus catatan ini", lalu banyak input mengikuti dan di bagian bawah ada tombol "perbarui catatan ini". Pengguna yang menekan enter saat berada di bidang di bagian bawah formulir tidak akan pernah curiga bahwa ia secara implisit mengenai "hapus catatan ini" dari atas.

Oleh karena itu saya pikir itu bukan ide yang baik untuk menggunakan tombol pertama atau lainnya yang pengguna tidak mendefinisikan (klik) satu. Namun demikian, browser melakukannya tentu saja.

Christopher K.
sumber
-2

EDIT: Maaf, ketika menulis jawaban ini saya berpikir tentang mengirimkan tombol dalam pengertian umum. Jawaban di bawah ini bukan tentang beberapa type="submit"tombol, karena hanya menyisakan satu type="submit"dan mengubah yang lain menjadi type="button". Saya meninggalkan jawabannya di sini sebagai referensi jika membantu seseorang yang dapat mengubah typedalam bentuk mereka:

Untuk menentukan tombol apa yang ditekan saat menekan masuk, Anda dapat menandainya type="submit", dan tombol lainnya menandainya type="button". Sebagai contoh:

<input type="button" value="Cancel" />
<input type="submit" value="Submit" />
Jesús Carrera
sumber
Ketik "tombol" tidak menyebabkan formulir untuk mengirim. Ini digunakan hanya untuk memicu skrip sisi klien.
Stewart
tepatnya, itu sebabnya browser melewatkannya saat Anda menekan enter, dan yang dengan tipe "kirim" dijalankan. Anda dapat menggunakan salah satu dengan ketik "tombol" untuk melakukan hal lain di klik misalnya. Harap hapus suara negatif.
Jesús Carrera
Pertanyaannya adalah tentang beberapa tombol kirim .
Stewart
Contoh saya benar-benar valid untuk beberapa tombol kirim. Yang dengan tipe "kirim" adalah yang ditentukan oleh browser untuk bertindak sebagai ditekan (yang merupakan pertanyaan tentang itu). Kemudian dengan tombol lain Anda dapat menggunakannya sebagai tombol kirim juga menggunakan peristiwa JavaScript seperti acara onClick yang Anda miliki dalam contoh Anda. Jadi jawaban saya relevan dan tidak pantas untuk dipilih. Tolong hapus itu.
Jesús Carrera
1
Jika maksud Anda adalah menghapus ambiguitas dengan membuat hanya satu di antaranya ketik "kirim" dan menggunakan JavaScript untuk mengimplementasikan tombol-tombol lain, maka ini merupakan duplikat dari balasan gambar dan dengan demikian telah dianggap sebagai ide buruk.
Stewart