JQuery UI Autocomplete с гибридным текстом/идентификатором

У меня возникли проблемы с созданием виджета автозаполнения jQuery для меня. Я использую список пар ключ/значение с сервера.

У меня следующие требования:

Если пользователь выбирает значение из виджета, я хочу передать идентификатор на сервер.

Если пользователь не выбирает значение и не вводит необработанный текст или не изменяет значение, которое уже было выбрано, я хочу, чтобы поле идентификатора было очищено и только исходный текст был отправлен на сервер.

Предположим, что someAjaxFunction возвращает массив объектов, которые ожидает виджет автозаполнения: {label:label, value:key}.

Сначала я установил виджет автозаполнения так:

$(input).autocomplete({
    source: sourceFunction,
    minLength: 1
});

Изменение выбора даже путем зависания над одним из элементов изменяет текст в текстовом поле, на который ссылается $(ввод), на основной ключ, а не на метку. Это очень нежелательно с точки зрения взаимодействия с пользователем - действительно, сама причина, по которой я исследую это, заключается в том, что пользователи сайта, который я создаю, постоянно сбиты с толку текстом, который они ввели, казалось бы, превратившись в случайные числа!

Я добавил скрытое поле в текстовое поле и реализовал события select() и focus(), чтобы скрыть идентификатор так:

$(input).autocomplete({
    source: sourceFunction,
    minLength: 1
    focus: function(event, ui) {
        $(idField).val(ui.item.value);
        $(this).val(ui.item.label);
        return false;
    },
    select: function(event, ui) {
        $(idField).val(ui.item.value);
        $(this).val(ui.item.label);
        return false;
    },
    minLength: 1
});

Это хорошо работает, когда пользователь придерживается script, предоставленного раскрывающимся списком автозаполнения. Идентификатор маскируется и правильно отправляется на сервер. К сожалению, если пользователь хочет ввести некоторый текст свободной формы в поле и выполнить поиск на основе этого значения, поле ID не будет reset, а ранее выбранный идентификатор будет отправлен на сервер. Это также довольно запутанно.

В документации по автозаполнению пользовательского интерфейса jQuery указано событие change и указано, что свойство item аргумента ui будет установлено на выбранный элемент. Я решил, что я могу reset скрытое поле id при нажатии клавиши и повторно заполнять идентификатор, если изменяется автозаполнение. К сожалению, в дополнение к событию нажатия клавиши, содержащему целую цепочку нажатий клавиш, которая не должна reset идентификатора, оператор return false в предыдущем случае select, который необходим для управления текстом в текстовом поле, предотвращает change от правильного присвоения ui.item.

Итак, теперь я застрял - я действительно не знаю, что еще я могу попытаться сделать функциональностью поддержки виджета, которая, похоже, должна поддерживаться по умолчанию. Либо этот процесс намного сложнее, чем должен быть, или я пропускаю что-то действительно очевидное. Я выбрал все доступные события и все примеры и пришел с пустыми руками. На самом деле даже пример "Пользовательские данные и отображение" на странице пользовательского интерфейса jQuery страдает этой проблемой.

Я могу добавить некоторые хаки на серверной стороне, чтобы покрыть это, но я действительно предпочел бы сделать это на уровне клиента.

Я также предпочел бы придерживаться виджета автозаполнения jQuery UI, а не переключаться на другой.

Ответ 1

Как я делаю autocomplete, нужно создать контейнер div, содержащий вход. Когда я выбираю элемент, я добавляю ссылку, содержащую span в контейнер, и я скрываю поле ввода.

Ссылка и диапазон стилизованы так, что она выглядит как кнопка с X и имеет обработчик события щелчка, чтобы удалить запись из DOM, очистить скрытое поле и повторно показать окно ввода при нажатии. Поэтому, когда выбран элемент:

  <div class="container">
    <a href="#"><span>Selected Item</span></a>
    <input id="myautocomplete" type="text" />
    <input type="hidden" name="myvalue" value="1" />
  </div>

И когда элемент не выбран:

 <div class="container">
    <input id="myautocomplete" name="myautocomplete" type="text" />
    <input id="myvalue" name="myvalue" type="hidden" value="" />
  </div>

Таким образом, вы либо вынуждены выбирать элемент, либо вводить текст свободной формы. На бэкэнд, если параметр запроса с ключом "myvalue" пуст, вы скорее посмотрите на параметр запроса с ключом "myautocomplete".

Ответ 2

Когда я предполагаю, что у вас установлены следующие поля:

<div>
    <input type="text" name="visible" class="autocomplete-reference" />
    <input type="hidden" name="hidden" />
</div>

Вам нужно выполнить init после js (он работает с jQuery 1.5.2):

$(document).ready(function() {
    $('.autocomplete-reference').each(function () {
        $(this).keydown(function(e){
            /*
            * this will reset hidden id reference on each visible field manual change
            * we have to bind it on keydown because we want to recognize event of submiting form by enter after autocomplete set
            */
            if (e.keyCode != 13) {
                $(this).siblings('input[type=hidden]').each(function () {
                    $(this).val('');
                });
            }
        });
        $(this).autocomplete({
            minLength: 1,
            /* you can set appending of autocomplete menu into some container to set css contextually
            appendTo: '#someElem',*/
            source: sourceFunction,
            search:function (event, ui) {
                //TODO ...spinner init...
            },
            open:function (event, ui) {
                /* you can grab autocomplete menu widget by this to manipulate some recognizing id, etc..
                 * $(this).autocomplete('widget')
                */
                //TODO ..stop spinner ...
                $(this).keydown(function(e){
                    /* this is important for live reference updates while arrow keys changes  */
                    if (e.keyCode == 37 || e.keyCode == 39) {
                       $($(this).data('autocomplete').menu.active).find('a').trigger('click');
                    }
                });
            },
            focus: function(event, ui) {
                /* here we'll map our data object onto both fields */
                $(this).val(ui.item.label);
                $(this).siblings('input[type=hidden]').each(function () {
                    $(this).val(ui.item.key);
                });
            },
            select: function(event, ui) {
                /* here we'll map our data object onto both fields */
                $(this).val(ui.item.label);
                $(this).siblings('input[type=hidden]').each(function () {
                    $(this).val(ui.item.key);
                });
            },
            close: function(event, ui) {
                //TODO ..stop spinner ...
            }
        });
    });
});

Очень приятно иметь некоторую проверку на стороне сервера, которая может конвертировать точные: видимые значения полей в ссылки для быстрого набора людей, конечно.

Ответ 3

Хотя это старый вопрос, мой метод может помочь.

В событии .change вы можете искать значение текстового поля со значением из вашего списка источников, используя цикл.

Goto для более подробной информации: здесь он находится в исходном списке Ajax, но тренировка аналогична. Поиск текста в JQuery AutoComplete Ui

Эта вещь беспокоила меня много раз, и в конце концов я понял это:)

Ответ 4

Вы можете использовать event.preventDefault

Соберите выбранные значения через ui.item.label или ui.item.value и получите необходимое значение и установите его в одно и то же текстовое поле.

var idNameCombo = ui.item.label;
            event.preventDefault();
            $("#mID").val(idNameCombo.split(",")[0].trim());