Javascript-форум (https://javascript.ru/forum/)
-   Элементы интерфейса (https://javascript.ru/forum/dom-window/)
-   -   input с автоДополнением (https://javascript.ru/forum/dom-window/1101-input-s-avtodopolneniem.html)

zem 18.03.2008 23:22

input с автоДополнением
 
Здравствуйте, Java script изучаю относительно недавно и столкнулся с такой проблемой:

на сервере есть база данных (MySQL), в ней содержится список фамилий (их может быть достаточно много, больше 1000). Требуется в форме во время ввода в текстовое поле (input) под ним отобразить список фамилий из этой БД, по мере ввода в поле, которые совпадают по начальным буквам. Т.е. примерно как это реализовано в google в строке поиска. Это необходимо для того чтобы гарантировать правильность написания фамилий в реальном времени.

Вопрос в основном в том, как грамотней поступить. Насколько я понимаю прямого доступа к MySQL JS получить не пожет чтобы делать соответствующие запросы БД по мере ввода букв. Значит во время загрузки страницы PHP должен создать массив с фамилиями для JS, с которым я дальше буду работать. Однако данный подход неэффективен в плане быстродействия если массив достаточно большой.

Кто сталкивался с подобными вещами подскажите пожалуйста как лучше поступить...

Dmitry A. Soshnikov 19.03.2008 01:24

zem,

Цитата:

Сообщение от zem
Значит во время загрузки страницы PHP должен создать массив с фамилиями для JS, с которым я дальше буду работать. Однако данный подход неэффективен в плане быстродействия если массив достаточно большой.

правильный ход мысли =) а значит дальше будет все просто:

- погуглите по запросам Ajax / XmlHtpRequest (можно до кучи посмотреть мою старую-старую статью - там как раз все разжеванно для начинающих. На этом сайте тоже должны быть статьи)

- далее, как изучите аякс:

-- создайте скрыйтый div с абсолютным позиционированием

-- по событию onkeyup (или onkeypress) input'a посылайте аякс запрос на сервер, чтобы получить данные из базы; параметром передавайте значение input'a

-- полученный результат положите в Ваш div и покажите его. Также надо будет пересчитать координаты дива (изменить свойства стиля left и top) согласно координатам input'a (как получить координаты - тоже посмотрите, куча тем), чтобы он отображался под input'ом, создавая подобие выпадающего списка

-- на событие onblur input'a можно повесить скрытие [и очистку] div'a

Андрей Параничев 19.03.2008 02:09

Вот, набросал в свободные 20 минут, может вам поможет.

Основной ход мысли такой:
* Ловить на input событие onKeyUp
* Посылать запрос на сервер с введённым текстом
* Получить ответ и составить из него ссылки в "нужное место".

Код (тут возможны неточности и не кросс-браузерные функции, писалось быстро, использовать только в качестве примера):
<html>
    <head>
        <script>
            var lnbox = {
                // Ссылка на DOM элемент поля ввода
                lninput: null,
                // Ссылка на DOM элемент всплывающего div'а
                lnelement: null,

                // Массив полученных фамилий
                lastnames: new Array(),
                
                // Объект XmlHttpRequest, для передачи данных (ajax)
                httpreq: window.XMLHttpRequest ? 
                        new XMLHttpRequest() : 
                        new ActiveXObject("Microsoft.XMLHTTP"),
            
            
            // Функция инициализации (выполняется по загрузке body)
            init: function() {
                // Устанавливаем ссылку на форму ввода
                this.lnelement = document.getElementById('lastnamebox');
                
                // Устанавливаем ссылку на вслывающий div
                this.lninput   = document.getElementById('lastnameinput');
                
                // Устанавливаем обработчик событий нажатой (точнее отпущенной)
                // клавиши на форму ввода
                this.lninput.onkeyup = function(e) {
                    lnbox.process(e);
                }
                
                // Устанавливаем обработчик ответа сервера
                this.httpreq.onreadystatechange = function() {
                    if (lnbox.httpreq.readyState == 4) 
                          lnbox.updateBox(lnbox.httpreq.responseText);
                }
            },
            
            
            // Функция запроса на сервер, параметр text - текст из поля ввода
            requestUpdate: function(text) {
                // Посылаем методом GET
                this.httpreq.open("GET", 'http://localhost/getlastnames.php?text='+ text +'&rand='+ Math.random());
                     this.httpreq.send(null);
            },
            
            
            // Функция обновления div'а с фамилиями, вызывается при ответе
            // с сервера, т.е обработчик ответа
            updateBox: function(answer) {
                // Полученный ответ парсим в js массив (подробнее читай JSON)
                this.lastnames = eval(answer);
                
                // Если пустой ответ - выходим из функции
                if(this.lastnames.length <= 0) return false;
                
                // Показываем div
                this.lnelement.style.display = 'block';
                
                // Отчищаем элемент от содержания
                this.lnelement.innerHTML = "";                
                    
                // Проходим циклом по массиву фамилий
                for(var i = 0; i < this.lastnames.length; i++)
                {
                    // Создаем элемент - тег <a>
                    var lnk = document.createElement('a');
                    
                    // Ставим заглушку в качестве ссылки
                    lnk.href = "javascript://";
                    
                    // Устанавливаем содержанием текущую фамилию
                    lnk.innerHTML = this.lastnames[i];
                    
                    // Ставим событие при щелчке на ссылку изменяется
                    // текст в форме ввода
                    lnk.onclick = function() {
                        lnbox.lninput.value = this.innerHTML;
                        
                        // Прячем div
                        lnbox.lnelement.innerHTML = '';
                        lnbox.lnelement.style.display = 'none';
                    }
                    
                    // Присоединяем элемент к div'у с ссылками
                    this.lnelement.appendChild(lnk);
                }
            },
            
            
            // Функция обработки события нажания (точнее отпускания) клавиши
            // на поле ввода
            process: function(event) {
                var key = window.event ? window.event.keyCode : (event.keyCode ? event.keyCode : (event.which ? event.which : null))                
                    
                  // Если введено меньше 2х символов не обрабатываем
                  if(this.lninput.value.length > 2)
                     this.requestUpdate(this.lninput.value);
                }
            }
        </script>
        <style>
            #lastnamebox {
                position: absolute;
                display: none;
                width: 180px;
                margin-top: 2px;
                border: 1px solid #;
                background: #F1F1F1;
            }
            
            #lastnamebox a:link,
            #lastnamebox a:visited {
                display: block;
                padding: 5px 0 5px 15px;
                color: #000000;
                font-size: 12px;
            }
            
            #lastnamebox a:hover {
                text-decoration: none;
                background: #FAFAFA;
                color: #666666;
            }
        </style>
    </head>
    <body onLoad="lnbox.init()">
        <input id="lastnameinput" type="text" size="30" />
        <div id="lastnamebox"></div>
    </body>
</html>

В этом коде конечно нужно провести оптимизацию: поставить http запрос на timeout (чтоб при печати слова не вызывалось при каждом символе), не делать запрос, если не изменилось содержание input'а (напр. при нажатии клавиш <Shitf>, <Alt>, ...), добавить переход по вариантам клавишей <Вниз> (ожидаемый функционал), убирать div на onBlur, и т.д и т.п...

PHP скрипт getlastnames.php (в данном примере такой адрес) должен возвращать массив фамилий в формате JSON, т.е например такой формат файла (самый простой):
<?php
header("Content-type: text/javascript; charset=UTF-8");
echo '["Андрей", "Борис", "Ванга", "Гриша", "Юрий", "Яша"]';


Этот php скрипт будет получать $_GET['text'], и по нему выбирать нужные варианты фамилий и выдавать их в формате JSON. Можно конечно отправлять сразу html результат, но это не рационально при использовании ajax.

zem 19.03.2008 09:34

Огромное спасибо ds [.code] и Андрей Параничев, не ожидал такой оперативности. Теперь знаю в каком направлении двигаться.


Часовой пояс GMT +3, время: 17:58.