Показать метки списка данных, но предоставить фактическое значение

98

В настоящее время <datalist>элемент HTML5 поддерживается в большинстве основных браузеров (кроме Safari) и кажется интересным способом добавления предложений во входные данные.

Однако, похоже, есть некоторые расхождения между реализацией valueатрибута и внутренним текстом в <option>. Например:

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

В разных браузерах это обрабатывается по-разному:

Chrome и Opera:
Даталист в Chrome / Opera

FireFox и IE 11:
Даталист в FireFox

После выбора одного из них ввод заполняется значением, а не внутренним текстом. Я хочу, чтобы пользователь видел только текст («Ответ») в раскрывающемся списке и во вводе, но передавал значение 42при отправке, как если selectбы.

Как сделать так, чтобы во всех браузерах в раскрывающемся списке отображались метки (внутренний текст) <option>s, но при отправке формы отправлялся valueатрибут?

Стефан Мюллер
источник
1
Я думаю, что Firefox и IE11 здесь не правы; согласно спецификациям One и Two , кажется, что он value=""должен иметь приоритет над строкой в ​​тегах, когда value=""объявлено. Таким образом, предлагается сделать «ответ» вашим атрибутом значения.
TylerH
1
@TylerH Нет - Firefox и IE11 здесь правильные: атрибут label предоставляет метку для элемента. Метка элемента option - это значение атрибута содержимого метки, если он есть, или, если он отсутствует, значение атрибута 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">

Таким образом, когда текст в исходном вводе изменяется, мы можем использовать javascript, чтобы проверить, присутствует ли текст в 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;
        }
    }
});

Идентификатор answerи answer-hiddenна обычном и скрытом вводе необходимы для того, чтобы скрипт знал, какой ввод принадлежит какой скрытой версии. Таким образом, inputна одной странице может быть несколько s, при этом один или несколько datalists предоставляют предложения.

Любой пользовательский ввод предоставляется как есть. Чтобы отправить пустое значение, когда пользовательский ввод отсутствует в списке данных, измените hiddenInput.value = inputValueнаhiddenInput.value = ""


Рабочие примеры jsFiddle: простой javascript и jQuery

Стефан Мюллер
источник
2
как бы вы поступили с вариантами с одним и тем же внутренним текстом, но с разными значениями данных? например jsfiddle.net/7k3sovht/78
bigbearzhu 03
1
Насколько я могу судить, нет возможности различать эти два варианта. Поскольку нет пользовательского события, которое можно было бы прослушать, невозможно узнать, какой из двух они фактически выбрали; все, что мы знаем, это какое значение оказалось в поле ввода.
Стефан Мюллер
@StephanMuller отличный ответ для тех, кто изучает HTML5, как я, спасибо! Как бы вы очистили текстовое поле для демонстрации после отправки?
Chris22
Чистый 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 ('значение-данных'));}});});
Петр Казусь
@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'); }
получено
1
Но что, если у вас есть две одинаковые подписи с разными значениями данных
Ричард Агирре,
1
Спасибо, Хизбалла Шах, вы действительно сэкономили столько часов
ABODE
5

Я понимаю, что это может быть немного поздно, но я наткнулся на это и задумался, как обрабатывать ситуации с несколькими идентичными значениями, но разными ключами (согласно комментарию bigbearzhu).

Поэтому я немного изменил ответ Стефана Мюллера:

Список данных с неуникальными значениями:

<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из datalistварианта вместо того , чтобы innerText.

Следующий код проверяет наличие optionс тем value, что выталкивает в скрытое поле и заменяет input.valueс 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;
      }

});

Как следствие, пользователь видит все, что указано в параметре innerText, но уникальный идентификатор option.valueдоступен при отправке формы. Демо jsFiddle

Cobbystreet
источник
Приятное дополнение :)
Стефан Мюллер
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>

Код выше позволяет форме содержать идентификатор выбранной опции.

23r0
источник
Это похоже на беспорядок и пахнет SQL-инъекцией. Не делай этого.
Fusseldieb 01
@ 23r0, некоторые отзывы о том, почему это могло быть отклонено; этот вопрос касается конкретно кода внешнего интерфейса. Включение внутреннего кода (например, PHP) может быть ненужным и сбивать с толку. Что касается HTML, я ожидаю, что вы получите только последнее customer_id_realотправленное значение , а не выбранное значение.
Джон