Здравствуйте! Сегодня я покажу Вам, каким образом можно создать текстовое поле с автозаполнением на JavaScript из базы данных, или же выбор из списка с возможностью фильтрации. Кстати, по поводу фильтрации, имеется похожий урок на тему фильтрация данных на JQuery, посмотрите, думаю может Вам тоже пригодиться.
Для подобного решения необходим минимальный набор элементов интерфейса, а именно поле для ввода строки, согласно которой будет происходить фильтрация и непосредственно список вариантов содержащих символы, введенные в текстовое поле. Но кроме этого, для большей функциональности я предлагаю добавить еще и скрытое поле на тот случай, если отображаемый перед пользователем текст не будет представлять собой непосредственно значение, необходимое для передачи серверу.
В итоге мы получаем следующую HTML структуру:
<form method="post" action="#"> <div class="ac-wrap"> <div class="input-wrap"> <input type="text"> <input name=""> div> <div class="list-wrap"> <ul>ul> div> div> form>
Далее рассмотрим CSS стили, примененные к данной структуре. Некоторые из них требуют особого внимания:
.ac-wrap{ // Данное свойство предотвращает наложение // низ лежащих элементов на наш список position:relative; } /* стили двух следующих селекторов необходимы для абсолютного растягивания текстового поля по контейнеру */ .input-wrap{ width:100%; height:100%; } .input-wrap input{ width:inherit; height:inherit; padding:0; border:none; } .list-wrap{ min-width:100%; /* следующие две строки ограничивают размеры контейнера списка, чтобы не растягивать страницу при значительных объемах данных, отображаемых в списке */ max-height:500px; overflow:auto; // скрываем список по умолчанию display:none; // решает проблемы при наложении элементов друг на друга position:absolute; }
Основа нашей страницы готова, теперь перейдем к написанию функций, обрабатывающих действия пользователя, а начнем обработки событий фокуса и ввода текста в поле:
var getList = function(e) { // Получаем указатель на контейнер списка (элемент, следующий за родительским) var container = e.target.parentNode.nextSibling.nextSibling; // Записываем введенный пользователем текст в объект формы var fd = new FormData(); fd.append(e.target.name, e.target.value); var xhr = new XMLHttpRequest(); xhr.open("POST", "./find.php", true); xhr.onreadystatechange = function (e) { if (e.target.readyState == 4) { // по завершению обработки запроса к серверу if (e.target.status == 200) { // если запрос выполнен успешно if (this.responseText) { // если от сервера пришел ответ, // формируем список и отображаем его при помощи функции pushList (описана ниже) pushList(this.responseText, container); } else { // если нет – прячем список container.style.display = "none"; } } } } // посылаем запрос xhr.send(fd); } var pushList = function(jsonStr, container) { container.style.display = "none"; // превращаем строку JSON формата в объект JavaScript var list = JSON.parse(jsonStr); // создаем пустой список var ul = document.createElement("ul"); // и наполняем его for (var i = 0; i < list.length; i++ ) { var li = document.createElement("li"); li.dataset.value = list[i]["value"]; li.innerHTML = list[i]["caption"]; ul.appendChild(li); } // после этого заменяем «новоиспеченным» ul тегом предыдущее содержимое // и отображаем блок со списком container.replaceChild(ul, container.firstChild); container.style.display = "block"; }
Как видно из кода приведенного выше, сервер должен возвращать строку в формате JSON.
Для примера этого урока формировал такую строку следующим образом:
$count = count($result); $responseStr = '['; for ($i = 0; $count > $i; $i++) { $responseStr .= "{"value":". $result[$i]["id"] .", "caption":"". $result[$i]["title"] .""}"; $responseStr .= (($count-1) > $i) ? ", " : ' '; } $responseStr .= ']';
Где $result – массив, содержащий записи, полученные из базы данных.
Обработчик события, описанный выше, устанавливаем следующим образом, так как страница может содержать более одного элемента рассматриваемого в этом уроке:
var acFields = document.querySelectorAll(".input-wrap input[type="text"]"); for (var i = 0; i < acFields.length; i++) { acFields[i].addEventListener("keyup", getList, false); acFields[i].addEventListener("focus", getList, false); }
Далее пишем обработчик события onclick для элементов списка, но так как изначально этих элементов не существует, поскольку они создаются автоматически, событие назначаем родительскому элементу:
var lists = document.querySelectorAll(".list-wrap"); for (var i = 0; i < lists.length; i++) { lists[i].addEventListener("click", setValue, true); } var setValue = function(e) { // если событие сработало на теге li, то есть на самом элементе списка if (e.target.tagName.toLowerCase() === "li") { // записываем указатель на контейнер списка var listWrap = e.target.parentNode.parentNode; var textField = listWrap.previousSibling.previousSibling.firstChild.nextSibling; // записываем значение и подпись выбранного элемента textField.value = e.target.textContent; textField.nextSibling.value = e.target.dataset.value; // скрываем список после осуществления выбора listWrap.style.display = "none"; } }
На этом создание автоматически заполняемого поля завершено. Благодарю за внимание!