Показати мітки даталістів, але подати фактичне значення


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 забезпечує мітку для елемента. Мітка елемента опції - це значення атрибута вмісту мітки, якщо він є, або, якщо його немає, значення атрибута IDL тексту тексту. w3.org/TR/html5/forms.html#attr-option-label
easwee

1
@easwee Це просто говорить, що мітка повинна бути тим, що є в етикетці, якщо є мітка, і що значення повинно бути тим, що є у значенні, якщо є значення. Він не визначає, який із них має перевагу.
TylerH

Відповіді:


114

Зверніть увагу, що datalistце не те саме, що a 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звичайний та прихований ввід потрібні сценарію, щоб знати, який вхід належить до якої прихованої версії. Таким чином, можна мати декілька inputs на одній сторінці з одним або декількома datalists, що пропонують пропозиції.

Будь-яке введення користувача подається як є. Щоб подати порожнє значення, коли введення даних користувача відсутнє в даталісті, змініть hiddenInput.value = inputValueнаhiddenInput.value = ""


Робочі приклади jsFiddle: звичайний javascript та jQuery


2
як би ви мали справу з варіантами з однаковим внутрішнім текстом, але різними значеннями даних? напр. jsfiddle.net/7k3sovht/78
bigbearzhu

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 ('data-value'));}});});
Piotr Kazuś

@StephanMuller дякую за обмін, дуже корисно, я працюю так, як ти кодував, однак я отримую значення даних просто під час використання зворотного простору у вході, а не під час надсилання або навіть вибору елемента diferenretn, що може бути не так?
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;


Сподіваюся, це допоможе.


Я отримую невизначену будь-яку причину?
Деджелл

1
Вирішуйте проблеми за допомогою console.log на кожному кроці. Переконайтеся, що ви використовуєте те саме значення ідентифікатора, яке ви викликаєте. І перевірити півколонки теж.
Хезбулла-шах

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
Але що, якщо у вас є два рівних титри з різними значеннями даних
Річард Агірре,

1
Дякую Хезбулла Шах, ви справді заощадили стільки годин
АБО

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


Гарне доповнення :)
Стівен Мюллер,

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>

Наведений вище код дозволяє формі містити ідентифікатор вибраної опції.


Це здається безладом і пахне введенням SQL. Не роби цього.
Fusseldieb

@ 23r0, деякі відгуки щодо того, чому це могло бути відхилено; це питання стосується спеціально коду інтерфейсу. Включення внутрішнього коду (наприклад, PHP) може бути непотрібним і заплутаним. Щодо HTML, я сподіваюся, ви отримаєте лише останнє значення для customer_id_realнадісланого, а не вибране значення.
Джон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.