แสดงป้ายชื่อดาต้าลิสต์ แต่ส่งค่าจริง


98

ปัจจุบัน<datalist>องค์ประกอบHTML5 ได้รับการสนับสนุนในเบราว์เซอร์หลัก ๆ ส่วนใหญ่ (ยกเว้น Safari) และดูเหมือนจะเป็นวิธีที่น่าสนใจในการเพิ่มคำแนะนำให้กับอินพุต

อย่างไรก็ตามดูเหมือนว่าจะมีความแตกต่างบางประการระหว่างการใช้งานvalueแอตทริบิวต์และข้อความด้านในของไฟล์<option>. ตัวอย่างเช่น:

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

เบราว์เซอร์ต่างๆจัดการสิ่งนี้แตกต่างกัน:

Chrome และ Opera:
Datalist ใน Chrome / Opera

FireFox และ IE 11:
Datalist ใน FireFox

หลังจากเลือกหนึ่งรายการอินพุตจะเต็มไปด้วยค่าไม่ใช่ข้อความด้านใน ฉันเพียงต้องการให้ผู้ใช้เห็นข้อความ ("คำตอบ") ในเมนูแบบเลื่อนลงและในอินพุต แต่ส่งผ่านค่า42เมื่อส่งเช่นเดียวกับที่selectต้องการ

ฉันจะทำให้เบราว์เซอร์ทั้งหมดมีรายการแบบเลื่อนลงแสดงป้าย (ข้อความด้านใน) ของ<option>s ได้อย่างไร แต่จะส่งvalueแอตทริบิวต์เมื่อส่งแบบฟอร์ม


1
ฉันคิดว่า Firefox และ IE11 ผิดที่นี่ ตามข้อกำหนดOne and Twoดูเหมือนว่าvalue=""ควรมีความสำคัญเหนือสตริงภายในแท็กเมื่อใดก็ตามที่มีการvalue=""ประกาศ ดังนั้นคำแนะนำคือให้ "คำตอบ" แอตทริบิวต์ค่าของคุณ
TylerH

1
@TylerH ไม่ใช่ - Firefox และ IE11 ถูกต้องที่นี่: แอตทริบิวต์ label มีป้ายกำกับสำหรับองค์ประกอบ เลเบลขององค์ประกอบตัวเลือกคือค่าของแอตทริบิวต์เนื้อหาป้ายกำกับหากมีหรือไม่มีค่าของแอตทริบิวต์ IDL ข้อความขององค์ประกอบ w3.org/TR/html5/forms.html#attr-option-label
easwee

1
@easwee นั่นแค่บอกว่าป้ายกำกับควรเป็นสิ่งที่อยู่ในฉลากถ้ามีป้ายกำกับและค่านั้นควรเป็นค่าอะไรถ้ามีค่า ไม่ได้ระบุว่าสิ่งใดมีความสำคัญเหนือกว่า
TylerH

คำตอบ:


113

โปรดทราบว่าdatalistไม่เหมือนกับไฟล์select. ช่วยให้ผู้ใช้ป้อนค่าแบบกำหนดเองที่ไม่ได้อยู่ในรายการและจะเรียกค่าอื่นสำหรับอินพุตดังกล่าวโดยไม่ได้กำหนดค่าไว้ก่อน

วิธีที่เป็นไปได้ในการจัดการอินพุตของผู้ใช้คือการส่งค่าที่ป้อนตามที่เป็นอยู่ส่งค่าว่างหรือป้องกันการส่ง คำตอบนี้จัดการเฉพาะสองตัวเลือกแรกเท่านั้น

หากคุณต้องการไม่อนุญาตให้ผู้ใช้ป้อนข้อมูลทั้งหมดอาจselectเป็นทางเลือกที่ดีกว่า


หากต้องการแสดงเฉพาะค่าข้อความของoptionรายการแบบเลื่อนลงเราใช้ข้อความด้านในสำหรับค่านั้นและไม่ต้องใช้valueแอตทริบิวต์ ค่าจริงที่เราต้องการส่งไปจะถูกเก็บไว้ในdata-valueแอตทริบิวต์ที่กำหนดเอง:

ในการส่งสิ่งนี้data-valueเราต้องใช้<input type="hidden">ไฟล์. ในกรณีนี้เราจะไม่name="answer"ใส่อินพุตปกติและย้ายไปยังสำเนาที่ซ่อนอยู่

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

วิธีนี้เมื่อข้อความในการป้อนข้อมูลเดิมที่มีการเปลี่ยนแปลงที่เราสามารถใช้จาวาสคริปต์ในการตรวจสอบว่าข้อความที่ยังอยู่ในและดึงข้อมูลของตนdatalist data-valueค่านั้นจะถูกแทรกลงในอินพุตที่ซ่อนและส่งแล้ว

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 answerและanswer-hiddenในอินพุตปกติและที่ซ่อนไว้เพื่อให้สคริปต์ทราบว่าอินพุตใดเป็นของเวอร์ชันที่ซ่อนอยู่ วิธีนี้เป็นไปได้ที่จะมีหลายรายการinputในหน้าเดียวกันโดยมีdatalistคำแนะนำอย่างน้อยหนึ่งรายการ

การป้อนข้อมูลของผู้ใช้จะถูกส่งตามที่เป็นอยู่ หากต้องการส่งค่าว่างเมื่อไม่มีอินพุตของผู้ใช้ในดาต้าลิสต์ให้เปลี่ยนhiddenInput.value = inputValueเป็นhiddenInput.value = ""


ตัวอย่างการทำงาน jsFiddle: javascript ธรรมดาและjQuery


2
คุณจะจัดการกับตัวเลือกที่มีอินเนอร์เท็กซ์เดียวกัน แต่ค่าข้อมูลต่างกันอย่างไร เช่นjsfiddle.net/7k3sovht/78
bigbearzhu

1
เท่าที่ฉันสามารถบอกได้ไม่มีทางที่จะแยกความแตกต่างระหว่างสองตัวเลือกนี้ เนื่องจากไม่มีเหตุการณ์ของผู้ใช้ที่จะรับฟังจึงเป็นไปไม่ได้ที่จะรู้ว่าพวกเขาเลือกทั้งสองแบบใด สิ่งที่เรารู้ก็คือค่าที่ลงเอยด้วยช่องป้อนข้อมูล
Stephan Muller

@StephanMuller คำตอบที่ดีสำหรับคนที่เรียนรู้ HTML5 มากขึ้นเช่นฉันขอบคุณ! คุณจะล้างกล่องข้อความสำหรับการสาธิตได้อย่างไรหลังจากส่ง
60

Pure jquery 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 + '- ซ่อน'). val ($ (this) .attr ('data-value'));}});});
Piotr Kazuś

@StephanMuller ขอบคุณสำหรับการแบ่งปันมีประโยชน์มากฉันทำงานตามที่คุณเขียนโค้ด แต่ฉันได้รับข้อมูล - ค่าเมื่อใช้ backspace ในอินพุตไม่ใช่เมื่อส่งหรือเลือกรายการที่แตกต่างกันมีอะไรผิดพลาดบ้าง
digitai

47

วิธีแก้ปัญหาที่ฉันใช้มีดังต่อไปนี้:

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

จากนั้นเข้าถึงค่าที่จะส่งไปยังเซิร์ฟเวอร์โดยใช้ JavaScript ดังนี้:

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


หวังว่าจะช่วยได้


ฉันไม่ได้กำหนดเหตุผลใด ๆ ?
Dejell

1
แก้ปัญหาด้วย console.log ในแต่ละขั้นตอน ตรวจสอบให้แน่ใจว่าคุณใช้ค่า ID เดียวกันกับที่คุณโทร และตรวจสอบอัฒภาคด้วย
Hezbullah Shah

1
วิธีนี้เป็นความคิดที่ดีมาก! - ฉันสามารถใช้วิธีแก้ปัญหานี้ได้ภายในไม่กี่นาที แรกที่ฉันของฉันการปรับปรุงองค์ประกอบที่มีคุณลักษณะinput data-value="1"จากนั้นฉันเขียนบล็อกต่อไปนี้ในสถานที่ที่มีการจับและใช้มูลค่า:if (typeof $(this).attr('data-value') != 'undefined') { var id = $(this).attr('name'); val = $('#'+id).find('option[value="'+val+'"]').attr('data-value'); }
WEBjuju

1
แต่จะเกิดอะไรขึ้นถ้าคุณมีคำบรรยายสองคำที่มีค่าเท่ากับข้อมูลที่แตกต่างกัน
Richard Aguirre

1
ขอบคุณ Hezbullah Shah ที่คุณประหยัดเวลาได้มาก
ABODE

5

ฉันรู้ว่านี่อาจจะช้าไปหน่อย แต่ฉันสะดุดกับสิ่งนี้และสงสัยว่าจะจัดการกับสถานการณ์ที่มีค่าเหมือนกันหลายค่า แต่คีย์ต่างกันอย่างไร (ตามความคิดเห็นของ bigbearzhu)

ดังนั้นฉันจึงแก้ไขคำตอบของ Stephan Muller เล็กน้อย:

ดาตาลิสต์ที่มีค่าไม่ซ้ำกัน:

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

เมื่อผู้ใช้เลือกตัวเลือกแทนที่เบราว์เซอร์input.valueที่มีvalueของตัวเลือกแทนdatalistinnerText

รหัสต่อไปนี้แล้วการตรวจสอบการoptionมีที่valueผลักดันที่เป็นข้อมูลที่ซ่อนอยู่และแทนที่ด้วยinput.valueinnerText

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

});

ด้วยเหตุนี้ผู้ใช้จึงเห็นสิ่งที่ตัวเลือกinnerTextระบุไว้ แต่ ID เฉพาะจากoption.valueสามารถใช้ได้เมื่อส่งแบบฟอร์ม สาธิต jsFiddle


นอกจากนี้ยังดี :)
Stephan Muller

1

เมื่อคลิกที่ปุ่มเพื่อค้นหาคุณสามารถค้นหาได้โดยไม่ต้องวนซ้ำ
เพียงเพิ่มตัวเลือกแอตทริบิวต์ที่มีค่าที่คุณต้องการ (เช่นid) และค้นหาเฉพาะ

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

-11

การใช้ PHP ฉันพบวิธีง่ายๆในการทำเช่นนี้ ผู้ชายแค่ใช้อะไรแบบนี้

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

โค้ดด้านบนช่วยให้แบบฟอร์มมี id ของตัวเลือกที่เลือกด้วย


ดูเหมือนจะเป็นระเบียบและมีกลิ่นเหมือนการฉีด SQL อย่าทำอย่างนั้น
Fusseldieb

@ 23r0 ข้อเสนอแนะบางประการเกี่ยวกับสาเหตุที่อาจได้รับการโหวตลง คำถามนี้เกี่ยวกับโค้ดส่วนหน้าโดยเฉพาะ การรวมโค้ดแบ็กเอนด์ (เช่น PHP) อาจไม่จำเป็นและทำให้สับสน เกี่ยวกับ HTML ฉันคาดว่าคุณจะได้รับเฉพาะค่าสุดท้ายสำหรับการcustomer_id_realส่งไม่ใช่ค่าที่เลือก
John
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.