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());