Hiển thị nhãn danh sách dữ liệu nhưng gửi giá trị thực tế


98

Hiện tại, <datalist>phần tử HTML5 được hỗ trợ trong hầu hết các trình duyệt chính (ngoại trừ Safari) và có vẻ như là một cách thú vị để thêm đề xuất vào đầu vào.

Tuy nhiên, dường như có một số khác biệt giữa việc triển khai valuethuộc tính và văn bản bên trong trên <option>. Ví dụ:

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

Điều này được xử lý khác nhau bởi các trình duyệt khác nhau:

Chrome và Opera:
Datalist trong Chrome / Opera

FireFox và IE 11:
Datalist trong FireFox

Sau khi chọn một, đầu vào được điền giá trị chứ không phải văn bản bên trong. Tôi chỉ muốn người dùng nhìn thấy văn bản ("Câu trả lời") trong menu thả xuống và trong đầu vào, nhưng chuyển giá trị 42khi gửi, giống như một select.

Làm cách nào để làm cho tất cả các trình duyệt có danh sách thả xuống hiển thị nhãn (văn bản bên trong) của các <option>s, nhưng gửi valuethuộc tính khi biểu mẫu được gửi?


1
Tôi nghĩ Firefox và IE11 đã sai ở đây; theo các thông số kỹ thuật MộtHai , có vẻ như nó value=""sẽ được ưu tiên hơn một chuỗi trong các thẻ, bất cứ khi nào có một value=""khai báo. Vì vậy, đề xuất sẽ là đặt "câu trả lời" thuộc tính giá trị của bạn.
TylerH

1
@TylerH Không - Firefox và IE11 đúng ở đây: Thuộc tính label cung cấp nhãn cho phần tử. Nhãn của phần tử tùy chọn là giá trị của thuộc tính nội dung nhãn, nếu có, hoặc nếu không có, giá trị của thuộc tính IDL văn bản của phần tử. w3.org/TR/html5/forms.html#attr-option-label
ambwee

1
@easwee Điều đó chỉ nói rằng nhãn phải là những gì trong nhãn nếu có nhãn và giá trị phải là những gì trong giá trị nếu có một giá trị. Nó không chỉ định cái nào được ưu tiên.
TylerH

Câu trả lời:


113

Lưu ý rằng datalistkhông giống như a select. Nó cho phép người dùng nhập một giá trị tùy chỉnh không có trong danh sách và sẽ không thể tìm nạp một giá trị thay thế cho đầu vào đó mà không xác định nó trước.

Các cách có thể để xử lý thông tin nhập của người dùng là gửi giá trị đã nhập nguyên trạng, gửi giá trị trống hoặc ngăn việc gửi. Câu trả lời này chỉ xử lý hai tùy chọn đầu tiên.

Nếu bạn muốn hoàn toàn không cho phép người dùng nhập, có lẽ selectsẽ là lựa chọn tốt hơn.


Để chỉ hiển thị giá trị văn bản của optionmenu thả xuống, chúng tôi sử dụng văn bản bên trong cho nó và loại bỏ valuethuộc tính. Giá trị thực tế mà chúng tôi muốn gửi được lưu trữ trong data-valuethuộc tính tùy chỉnh :

Để gửi cái này, data-valuechúng tôi phải sử dụng một <input type="hidden">. Trong trường hợp này, chúng tôi loại bỏ name="answer"thông tin đầu vào thông thường và chuyển nó vào bản sao ẩn.

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

Bằng cách này, khi văn bản trong đầu vào ban đầu thay đổi, chúng ta có thể sử dụng javascript để kiểm tra xem văn bản có hiện diện trong datalistvà tìm nạp nó hay không data-value. Giá trị đó được chèn vào đầu vào ẩn và được gửi.

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 answeranswer-hiddentrên đầu vào thông thường và đầu vào ẩn là cần thiết để tập lệnh biết đầu vào nào thuộc phiên bản ẩn nào. Bằng cách này, có thể có nhiều người inputtrên cùng một trang với một hoặc nhiều người datalistcung cấp đề xuất.

Mọi đầu vào của người dùng đều được gửi nguyên trạng. Để gửi một giá trị trống khi đầu vào của người dùng không có trong danh sách dữ liệu, hãy thay đổi hiddenInput.value = inputValuethànhhiddenInput.value = ""


Các ví dụ về jsFiddle đang làm việc: javascript thuầnjQuery


2
bạn sẽ xử lý như thế nào với các tùy chọn có cùng nội dung nhưng dữ liệu-giá trị khác nhau? ví dụ jsfiddle.net/7k3sovht/78
bigbearzhu

1
Theo như tôi có thể nói, không có cách nào để phân biệt giữa hai lựa chọn. Vì không có sự kiện người dùng nào để lắng nghe nên không thể biết họ thực sự đã chọn cái nào; tất cả những gì chúng ta biết là giá trị nào đã kết thúc trong trường đầu vào.
Stephan Muller

@StephanMuller câu trả lời tuyệt vời cho một người đang học thêm HTML5 như tôi, cảm ơn! Làm thế nào bạn sẽ xóa hộp văn bản cho bản trình diễn sau khi gửi?
Chris 22

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 + '- hidden'). val ($ (this) .attr ('data-value'));}});});
Piotr Kazuś

@StephanMuller cảm ơn bạn đã chia sẻ, rất hữu ích, tôi đang chạy khi bạn viết mã, tuy nhiên tôi nhận được giá trị dữ liệu chỉ khi sử dụng backspace trong đầu vào, không phải khi gửi hoặc thậm chí chọn một mục khác nhau, điều gì có thể bị sai?
digitai

47

Giải pháp tôi sử dụng như sau:

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

Sau đó, truy cập giá trị sẽ được gửi đến máy chủ bằng JavaScript như sau:

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


Hy vọng nó giúp.


Tôi đang nhận được bất kỳ lý do không xác định?
Dejell

1
Sự cố chụp với console.log ở mỗi bước. Đảm bảo rằng bạn đang sử dụng cùng một giá trị id mà bạn đang gọi. Và kiểm tra semicollons nữa.
Hezbullah Shah

1
giải pháp này là một ý tưởng tuyệt vời! - Tôi có thể, nói một cách đơn giản, thực hiện giải pháp này trong vài phút. đầu tiên tôi cập nhật inputphần tử của mình bằng thuộc tính data-value="1". Sau đó, tôi đã viết khối sau ở những nơi giá trị đang được lấy và sử dụng:if (typeof $(this).attr('data-value') != 'undefined') { var id = $(this).attr('name'); val = $('#'+id).find('option[value="'+val+'"]').attr('data-value'); }
WEBjuju

1
Nhưng điều gì sẽ xảy ra nếu bạn có hai chú thích bằng nhau với một số giá trị dữ liệu khác nhau
Richard Aguirre

1
Cảm ơn Hezbullah Shah, bạn thực sự đã tiết kiệm được rất nhiều giờ
ABODE vào

5

Tôi nhận ra điều này có thể hơi muộn, nhưng tôi đã tình cờ phát hiện ra điều này và đang tự hỏi làm thế nào để xử lý các tình huống có nhiều giá trị giống nhau nhưng các khóa khác nhau (theo nhận xét của bigbearzhu).

Vì vậy, tôi đã sửa đổi một chút câu trả lời của Stephan Muller:

Một danh sách dữ liệu có các giá trị không phải là duy nhất:

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

Khi người sử dụng chọn một lựa chọn, này thay thế trình duyệt input.valuevới valuecác datalisttùy chọn thay cho innerText.

Sau đó, mã sau sẽ kiểm tra một optionvới cái đó value, đẩy cái đó vào trường ẩn và thay thế input.valuebằng 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;
      }

});

Do đó, người dùng thấy bất cứ điều gì tùy chọn innerTextnói, nhưng id duy nhất từ ​​đó option.valuesẽ có sẵn khi gửi biểu mẫu. Demo jsFiddle


Bổ sung tốt đẹp :)
Stephan Muller

1

Khi nhấp vào nút tìm kiếm, bạn có thể tìm thấy nó mà không cần vòng lặp.
Chỉ cần thêm vào tùy chọn một thuộc tính với giá trị bạn cần (như id) và tìm kiếm nó cụ thể.

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

-11

Sử dụng PHP, tôi đã tìm thấy một cách khá đơn giản để làm điều này. Guys, chỉ cần sử dụng một cái gì đó như thế này

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

Mã trên cho phép biểu mẫu mang id của tùy chọn cũng được chọn.


Điều đó có vẻ giống như một mớ hỗn độn và có mùi giống như SQL injection. Đừng làm vậy.
Fusseldieb

@ 23r0, một số phản hồi tại sao điều này có thể đã bị bỏ phiếu; câu hỏi này là về mã giao diện người dùng cụ thể. Bao gồm mã phụ trợ (như PHP) có thể không cần thiết và khó hiểu. Về HTML, tôi hy vọng bạn sẽ chỉ nhận được giá trị cuối cùng cho giá trị customer_id_realđã gửi chứ không phải giá trị đã chọn.
John
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.