6 февраля 2014
10880
автозаполнение на JavaScript

Автозаполнение на JavaScript

JavaScript
Демонстрация » Скачать »

Здравствуйте! Сегодня я покажу Вам, каким образом можно создать текстовое поле с автозаполнением на 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";
         }
}

 

На этом создание автоматически заполняемого поля завершено. Благодарю за внимание!