Tunjukkan label datalist tetapi kirimkan nilai sebenarnya

98

Saat ini <datalist>elemen HTML5 didukung di sebagian besar browser utama (kecuali Safari) dan sepertinya cara yang menarik untuk menambahkan saran ke masukan.

Namun, tampaknya ada beberapa perbedaan antara implementasi valueatribut dan teks bagian dalam pada <option>. Sebagai contoh:

<input list="answers" name="answer">
<datalist id="answers">
  <option value="42">The answer</option>
</datalist>

Ini ditangani secara berbeda oleh browser yang berbeda:

Chrome dan Opera:
Datalist di Chrome / Opera

FireFox dan IE 11:
Datalist di FireFox

Setelah memilih satu, masukan diisi dengan nilai dan bukan teks bagian dalam. Saya hanya ingin pengguna melihat teks ("Jawaban") di dropdown dan di input, tetapi meneruskan nilai 42saat mengirimkan, seperti keinginan select.

Bagaimana saya bisa membuat semua browser memiliki daftar dropdown yang menunjukkan label (teks bagian dalam) <option>s, tetapi mengirimkan valueatribut saat formulir dikirimkan?

Stephan Muller
sumber
1
Saya pikir Firefox dan IE11 salah di sini; menurut spesifikasi Satu dan Dua , tampaknya itu value=""harus didahulukan daripada string di dalam tag, setiap kali ada yang value=""dideklarasikan. Jadi sarannya adalah menjadikan "jawaban" sebagai atribut nilai Anda.
TylerH
1
@TylerH No - Firefox dan IE11 benar di sini: Atribut label memberikan label untuk elemen. Label dari elemen opsi adalah nilai atribut konten label, jika ada, atau, jika tidak ada, nilai atribut IDL teks elemen. w3.org/TR/html5/forms.html#attr-option-label
easwee
1
@easwee Itu hanya mengatakan label harus apa yang ada di label jika ada label, dan nilai harus sesuai dengan nilai jika ada nilai. Itu tidak menentukan mana yang diutamakan.
TylerH

Jawaban:

113

Perhatikan bahwa datalisttidak sama dengan a select. Ini memungkinkan pengguna memasukkan nilai khusus yang tidak ada dalam daftar, dan tidak mungkin mengambil nilai alternatif untuk masukan seperti itu tanpa menentukannya terlebih dahulu.

Cara yang mungkin untuk menangani masukan pengguna adalah dengan mengirimkan nilai yang dimasukkan sebagaimana adanya, mengirimkan nilai kosong, atau mencegah pengiriman. Jawaban ini hanya menangani dua opsi pertama.

Jika Anda ingin melarang masukan pengguna sepenuhnya, mungkin selectakan menjadi pilihan yang lebih baik.


Untuk hanya menampilkan nilai teks dari optiondalam dropdown, kami menggunakan teks bagian dalam untuk itu dan meninggalkan valueatributnya. Nilai sebenarnya yang ingin kami kirimkan disimpan dalam data-valueatribut khusus :

Untuk mengirimkan ini data-valuekita harus menggunakan file <input type="hidden">. Dalam hal ini kita membiarkan name="answer"input reguler dan memindahkannya ke salinan tersembunyi.

<input list="suggestionList" id="answerInput">
<datalist id="suggestionList">
    <option data-value="42">The answer</option>
</datalist>
<input type="hidden" name="answer" id="answerInput-hidden">

Dengan cara ini, ketika teks dalam masukan asli berubah, kita dapat menggunakan javascript untuk memeriksa apakah teks juga ada di datalistdan mengambilnya data-value. Nilai itu dimasukkan ke dalam input tersembunyi dan dikirimkan.

document.querySelector('input[list]').addEventListener('input', function(e) {
    var input = e.target,
        list = input.getAttribute('list'),
        options = document.querySelectorAll('#' + list + ' option'),
        hiddenInput = document.getElementById(input.getAttribute('id') + '-hidden'),
        inputValue = input.value;

    hiddenInput.value = inputValue;

    for(var i = 0; i < options.length; i++) {
        var option = options[i];

        if(option.innerText === inputValue) {
            hiddenInput.value = option.getAttribute('data-value');
            break;
        }
    }
});

Id answerdan answer-hiddenpada input reguler dan tersembunyi diperlukan agar skrip mengetahui input mana yang termasuk dalam versi tersembunyi mana. Dengan cara ini dimungkinkan untuk memiliki beberapa inputs pada halaman yang sama dengan satu atau lebih datalists memberikan saran.

Setiap masukan pengguna dikirimkan apa adanya. Untuk mengirimkan nilai kosong saat input pengguna tidak ada di datalist, ubah hiddenInput.value = inputValuekehiddenInput.value = ""


Contoh jsFiddle yang berfungsi: javascript dan jQuery biasa

Stephan Muller
sumber
2
bagaimana Anda menangani opsi dengan teks dalam yang sama tetapi nilai data yang berbeda? misalnya jsfiddle.net/7k3sovht/78
bigbearzhu
1
Sejauh yang saya tahu, tidak ada cara untuk membedakan kedua opsi tersebut. Karena tidak ada peristiwa pengguna untuk didengarkan, tidak mungkin untuk mengetahui yang mana di antara keduanya yang sebenarnya mereka pilih; semua yang kita tahu adalah nilai apa yang berakhir di bidang input.
Stephan Muller
@StephanMuller jawaban yang bagus untuk seseorang yang belajar lebih banyak HTML5 seperti saya, terima kasih! Bagaimana Anda membersihkan kotak teks untuk demo setelah mengirimkan?
Chris22
Jquery murni document.querySelector ('input [list]'). AddEventListener ('input', function (e) {var value = $ (this) .val (); var list = $ (this) .attr ('list' ); var id = $ (this) .attr ('id'); $ ('#' + list + 'option'). each (function () {if ($ (this) .val () == value) { $ ('#' + id + '- hidden'). val ($ (this) .attr ('data-value'));}});});
Piotr Kazuś
@StephanMuller terima kasih telah berbagi, sangat berguna, saya menjalankan seperti yang Anda kodekan, namun saya mendapatkan nilai data hanya saat menggunakan backspace di input, bukan saat mengirimkan atau bahkan memilih item yang berbeda, apa yang salah?
digitai
47

Solusi yang saya gunakan adalah sebagai berikut:

<input list="answers" id="answer">
<datalist id="answers">
  <option data-value="42" value="The answer">
</datalist>

Kemudian akses nilai yang akan dikirim ke server menggunakan JavaScript seperti ini:

var shownVal = document.getElementById("answer").value;
var value2send = document.querySelector("#answers option[value='"+shownVal+"']").dataset.value;


Semoga membantu.

Hezbullah Shah
sumber
Saya mendapatkan alasan yang tidak ditentukan?
Dejell
1
Tembak masalah dengan console.log di setiap langkah. Pastikan Anda menggunakan nilai id yang sama dengan yang Anda panggil. Dan periksa juga titik koma.
Hezbullah Shah
1
solusi ini adalah ide yang bagus! - Saya dapat, cukup sederhana, menerapkan solusi ini dalam hitungan menit. pertama saya memperbarui inputelemen saya dengan atribut data-value="1". Kemudian saya menulis blok berikut di tempat-tempat di mana nilainya diambil dan digunakan:if (typeof $(this).attr('data-value') != 'undefined') { var id = $(this).attr('name'); val = $('#'+id).find('option[value="'+val+'"]').attr('data-value'); }
WEBjuju
1
Tetapi bagaimana jika Anda memiliki dua teks yang sama dengan beberapa nilai data yang berbeda
Richard Aguirre
1
Terima kasih Hezbullah Shah Anda benar-benar menghemat begitu banyak jam
ABODE
5

Saya menyadari ini mungkin agak terlambat, tetapi saya menemukan ini dan bertanya-tanya bagaimana menangani situasi dengan beberapa nilai yang identik, tetapi kunci yang berbeda (sesuai komentar bigbearzhu).

Jadi saya sedikit mengubah jawaban Stephan Muller:

Seorang datalist dengan nilai non-unik:

<input list="answers" name="answer" id="answerInput">
<datalist id="answers">
  <option value="42">The answer</option>
  <option value="43">The answer</option>
  <option value="44">Another Answer</option>
</datalist>
<input type="hidden" name="answer" id="answerInput-hidden">

Ketika pengguna memilih opsi, menggantikan browser yang input.valuedengan valuesatu datalistpilihan bukan innerText.

Kode berikut kemudian memeriksa optiondengan itu value, mendorongnya ke bidang tersembunyi dan menggantikan input.valuedengan innerText.

document.querySelector('#answerInput').addEventListener('input', function(e) {
    var input = e.target,   
        list = input.getAttribute('list'),
        options = document.querySelectorAll('#' + list + ' option[value="'+input.value+'"]'),
        hiddenInput = document.getElementById(input.getAttribute('id') + '-hidden');

    if (options.length > 0) {
      hiddenInput.value = input.value;
      input.value = options[0].innerText;
      }

});

Akibatnya, pengguna melihat apa pun yang innerTextdikatakan opsi tersebut , tetapi ID unik dari option.valuetersedia saat pengiriman formulir. Demo jsFiddle

cobbystreet.dll
sumber
Tambahan yang bagus :)
Stephan Muller
1

Saat mengklik tombol pencarian, Anda dapat menemukannya tanpa loop.
Cukup tambahkan ke opsi atribut dengan nilai yang Anda butuhkan (suka id) dan cari secara spesifik.

$('#search_wrapper button').on('click', function(){
console.log($('option[value="'+ 
$('#autocomplete_input').val() +'"]').data('value'));
})
Gal Albalak
sumber
-11

Menggunakan PHP saya telah menemukan cara yang cukup sederhana untuk melakukan ini. Teman-teman, Gunakan saja sesuatu seperti ini

<input list="customers" name="customer_id" required class="form-control" placeholder="Customer Name">
            <datalist id="customers">
                <?php 
    $querySnamex = "SELECT * FROM `customer` WHERE fname!='' AND lname!='' order by customer_id ASC";
    $resultSnamex = mysqli_query($con,$querySnamex) or die(mysql_error());

                while ($row_this = mysqli_fetch_array($resultSnamex)) {
                    echo '<option data-value="'.$row_this['customer_id'].'">'.$row_this['fname'].' '.$row_this['lname'].'</option>
                    <input type="hidden" name="customer_id_real" value="'.$row_this['customer_id'].'" id="answerInput-hidden">';
                }

                 ?>
            </datalist>

Kode Di Atas memungkinkan formulir membawa id dari opsi yang juga dipilih.

23r0
sumber
Sepertinya berantakan dan baunya seperti injeksi SQL. Jangan lakukan itu.
Fusseldieb
@ 23r0, beberapa umpan balik tentang mengapa ini mungkin ditolak; pertanyaan ini secara khusus adalah tentang kode frontend. Menyertakan kode backend (seperti PHP) mungkin tidak perlu dan membingungkan. Mengenai HTML, saya berharap Anda hanya akan mendapatkan nilai terakhir untuk customer_id_realdikirimkan, bukan nilai yang dipilih.
Yohanes