Связанные с помощью ajax списки (select)

В этой статье будет рассказано как с помощь jQuery сделать автоматически подгружаемые списки без перезагрузки страницы.

1. Подготовка

Сначала необходимо загрузить последнюю версию jQuery — на сайте http://jquery.com находим кнопочку Download (jQuery); и нажимаем её.

2. Отрисуем форму для наглядности

<!-- подключаем jquery -->
<script type="text/javascript" src="jquery.js"></script>
<!-- отрисовываем форму -->
<form action="#" method="get">
    <p>Страна</p>
    <select name="country_id" id="country_id">
        <option value="0">- выберите страну -</option>
        <option value="1">Россия</option>
        <option value="2">Украина</option>
        <option value="3">Беларусь</option>
    </select>
    <p>Город:</p>
    <select name="region_id" id="region_id" disabled="disabled">
        <option value="0">- выберите город -</option>
    </select>
</form>

Что нам необходимо?
При выборе страны, послать AJAX запрос на сервер, получить список городов в стране и подставить во второй селект.

Что мы для этого сделаем?
Необходимо повесить обработчик события onchange на select с id=country_id, т.е. при выборе страны мы хотим вызвать свою функцию, которая будет подгружать список городов.

3. Бэк-енд и фронт-энд

Наше так называемое веб-приложение будет состоять из двух частей: бэк-энд и фронт-энд (серверная часть и клиентская). Как многие уже догадались, за клиентскую часть отвечать будет javascript, а за серверную — php.

3.1. Фронт-энд

Здесь описана с подробными комментариями функция, которая будет вызываться при выборе страны:

/*
* При полной загрузке документа
* мы начинаем определять события
*/
$(document).ready(function () {
    /*
     * На выборе селекта страны — вешаем событие,
     * функция будет брать значение этого селекта 
     * и с помощью ajax запроса получать список
     * городов для вставки в следующий селект 
     */
    $('#country_id').change(function () {
        /*
         * В переменную country_id положим значение селекта
         * (выбранная страна)
         */
        var country_id = $(this).val();
        /*
         * Если значение селекта равно 0,
         * т.е. не выбрана страна, то мы
         * не будем ничего делать
         */ 
        if (country_id == '0') {
            $('#region_id').html('<option>- выберите город -</option>');
            $('#region_id').attr('disabled', true);
            return(false);
        }
        /*
         * Очищаем второй селект с городами
         * и блокируем его через атрибут disabled
         * туда мы будем класть результат запроса
         */
        $('#region_id').attr('disabled', true);
        $('#region_id').html('<option>загрузка...</option>');
        /*
         * url запроса городов
         */
        var url = 'get_regions.php';

        /*
         * GET'овый AJAX запрос
         * подробнее о синтаксисе читайте
         * на сайте http://docs.jquery.com/Ajax/jQuery.get
         * Данные будем кодировать с помощью JSON
         */
        $.get(
            url,
            "country_id=" + country_id,
            function (result) {
                /*
                 * В случае неудачи мы получим результат с type равным error.
                 * Если все прошло успешно, то в type будет success,
                 * а также массив regions, содержащий данные по городам
                 * в формате 'id'=>'1', 'title'=>'название города'.
                 */
                if (result.type == 'error') {
                    /*
                     * ошибка в запросе
                     */
                    alert('error');
                    return(false);
                }
                else {
                    /*
                     * проходимся по пришедшему от бэк-энда массиву циклом
                     */
                    var options = '';
                    $(result.regions).each(function() {
                        /*
                         * и добавляем в селект по городу
                         */
                        options += '<option value="' + $(this).attr('id') + '">' + $(this).attr('title') + '</option>';
                    });
                    $('#region_id').html(options);
                    $('#region_id').attr('disabled', false);
                }
            },
            "json"
        );
    });
});

3.2. Бэк-энд

Как мы уже договорились, бэк-энд будет на php.
Рядом со скриптом мы положим 3 файлика — 1.txt, 2.txt и 3.txt, там будут города России, Украины и Беларуси.
Сам скрипт:

<?php

/*
 * Имитируем долгий и нудный ajax запрос
 * В рабочем проекте конечно же убрать
 */
sleep(rand(1,3));

/*
 * Мы получаем GET параметром id страны и подгружаем список городов по этому id.
 */
$country_id = @intval($_GET['country_id']);

if (file_exists(dirname(__FILE__) . '/' . $country_id . '.txt')) {
    $regions = array();
    $regs = file(dirname(__FILE__) . '/' . $country_id . '.txt');
    $i=1;
    foreach ($regs as $r) {
        $regions[] = array('id'=>$i, 'title'=>trim($r));
        $i++;
    }

    $result = array('type'=>'success', 'regions'=>$regions);
}
else {
    $result = array('type'=>'error');
}

/*
 * Упаковываем данные с помощью JSON
 */
print json_encode($result);

?>
А у меня все в базе?

Без проблем, можете, используя country_id, вытаскивать города из базы, если храните данные в ней.

Пример с БД MySQL:

include_once 'connect.php';
$country_id = @intval($_GET['country_id']);

$regs=mysql_query("SELECT name FROM region WHERE country_id=$country_id"); 
if ($regs) {

$num = mysql_num_rows($regs); 
$regions = array();

for ($i=0; $i<$num; $i++) 
$region[$i] = mysql_fetch_row($regs);

$i=0;
	foreach ($region as $r) {
		$regions[] = array('id'=>$i, 'title'=>$r);
		$i++;
	} 
$result = array('type'=>'success', 'regions'=>$regions);  
}
else {
	$result = array('type'=>'error');
}

/*
 * Упаковываем данные с помощью JSON
 */
print json_encode($result);

4. Кодировки

Не стоит забывать, что для ajax-запросов необходима кодировка utf-8. Еще не перешли? — Давно пора.

Весь проект не переписать под utf?
Хорошо, существует iconv() — функция позволяющая менять кодировку.

5. Результаты

Таким образом, у нас получилось: 1 html страница с javascript кодом (который, впринципе, можно вынести в отдельный скрипт), подключаемая библиотека jquery, php бэк-энд и 3 файлика с городами. Демо здесь. А сам скрипт можно скачать тут.

6. Важное замечание

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


Комментарии: