xandeadx.ru Блог музицирующего веб-девелопера

Javascript → Создаём зависимые списки с помощью jQuery и AJAX

Опубликовано в

Зависимые списки — это два и более select-a, в которых список одного select-a зависит от выбранного значения другого. Например выбрав в первом списке страну, второй список заполняется городами выбранной страны.

поиск ВКонтакте

Такой приём очень популярен ВКонтакте и других соц. сетях.

Сейчас мы создадим простой зависимый список ОбластьГород.

Для начала нам понадобится список областей и городов в формате

<?php // файл city.php
 
$city = array (
  'Москва и Московская обл.' => array (
    0 => 'Москва',
    1 => 'Абрамцево',
    // ...
  ),
  'Санкт-Петербург и область' => array (
    0 => 'Санкт-Петербург',
    1 => 'Александровская',
    // ...
  ),
  // ...
);
 
?>

Создаём два select-а, в одном будут области, в другой будут подгружаться города:

<select name="region" onchange="loadCity(this)">
    <option></option>
 
    <?php // заполняем список областей
    foreach ($city as $region => $cityList)
    {
        echo '<option value="' . $region . '">' . $region . '</option>' . "\n";
    }
    ?>
 
</select>
 
<select name="city" disabled="disabled">
    <option>Выберите область</option>
</select>

При выборе области, сработает функция loadCity, которая подгрузит список городов. Определим её:

function loadCity(select)
{
    var citySelect = $('select[name="city"]');
 
    // послыаем AJAX запрос, который вернёт список городов для выбранной области
    $.getJSON('index.php', {action:'getCity', region:select.value}, function(cityList){
        citySelect.html(''); // очищаем список городов
 
        // заполняем список городов новыми пришедшими данными
        $.each(cityList, function(i){
            citySelect.append('<option value="' + i + '">' + this + '</option>');
        });
    });
}

Ну и php скрипт который отдаст в JSON формате список городов конкретной области:

<?php // файл index.php
 
require_once('city.php');
 
if (isset($_GET['action']) && $_GET['action'] == 'getCity')
{
    if (isset($city[$_GET['region']]))
    {
        echo json_encode($city[$_GET['region']]); // возвращаем данные в JSON формате;
    }
    else
    {
        echo json_encode(array('Выберите область'));
    }
 
    exit;
}
 
?>

Примечание: все файлы должны быть в кодировке UTF-8 without BOM, а сервер должен отдавать заголовки с правильно указанным charset (для этого в исходниках есть файл .htaccess).

Пример + Архив с исходниками.

Похожие записи

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

а нельзя ли рассказать как это должно выглядеть в Smarty

так и должно выглядеть :) только при формировании html, вместо php-шного foreach нужно использовать свой

млин я даже массив не могу построить
может поможете

вам не обязательно иметь формат массива как у меня в файле city.php, можно сделать так:

$result = mysql_query("SELECT id, name FROM cantry");
$cantrylist = array();
 
// формируем массив стран
while ($row = mysql_fetch_array($result))
{
    $cantrylist[$row['id']] = $row['name'];
}
 
// добавляем массив в smarty
$smarty->assign('cantrylist', $cantrylist);

Smarty шаблон:

<select name="region" onchange="loadCity(this)">
    <option></option>
 
    {foreach from=$cantrylist key=id item=name}
    <option value="{$id}">{$name}</option>
    {/foreach}
 
</select>

ну это мы получили только список стран, а где теперь выбрать список городов соответственно к странам(

в том месте где обрабатываете AJAX запрос:

if ($_GET['action'] == 'getCity')
{
    $result = mysql_query ("SELECT id, name FROM siti WHERE cant_id = '" . (int)$_GET['region'] . "' ");
    $citylist = array();
 
    while ($row = mysql_fetch_array($citylist))
    {
        $citylist[$row['id']] = $row['name'];
    }
 
    echo json_encode($citylist); // возвращаем данные в JSON формате;
    exit;
}

xandeadx, не поможете реализовать данный пример с db. Опять застрял.
В постах видел элементы работы с db? но включить не получилось. с утра парюсь.
В предыдущем посте я выставил "битые исходники" - не могли бы Вы дополнить их .. как надо правильно. Наверное, этот вариант был бы интересен многим, не только мне.
Заранее благодарен за помощь и понимание!

но включить не получилось

в чём конкретно сложность? там же всё элементарно, вместо подключения файла city.php делаете запрос к бд

Есть старая таблица - "дерево". Я хотел в левую часть(списка) поместить категории в правую подкатегории. Если заменить вместо обычного массива – один запрос к базе ...(тут не получается создать тот многомерный массив как у вас) , хотя бы потому что нужно делать 2 запроса
Выводил по этому принципу: $include_array[$row['ID']] = $row['Title'];
Мне кажется было бы логичней с помощью одного запроса выводить в форме первый селект.
А вторым запросом – подгружать. Не знаю как правильно решить данный ребус.
P/S –с двумя запросами я не справился.. первый, нормально заполнил селект. А второй запрос смешиваясь с JS – не загружается..
Если есть время и не сильно озадачил, помогите пожалуйста. Спасибо.

Скажите, а возможно ли реализовать ..например, тройной селект? Если да, то каким образом?
по идее, как только образовался втрой id - можно сразу "проявить" третий. :)
мысленно вроде не сложно, но нет сил в query

возможно ли реализовать ..например, тройной селект?

возможно

Если да, то каким образом?

аналогично второму

Скажите, как сильно влияет кодировка при работе с jquery. Я смотрю все сплошь и рядом используют utf8. Хотел сейчас попробовать прикрутить в один из своих проектов, пока не работает.. вот и возник вопрос, может ли не работать данный пример если будет в стандартной - 1251 - а мы туда втискиваем js(utf8). Под "не работает" я подразумеваю полностью не нерабочий пример! ..а не просто битый текст. :)
И как правильно поступить если все построено на - 1251. ..прокладки? mysql_query("SET NAMES 'utf8'"); - мне кажется тоже не вариант... :)

Здравствуйте!
Появился вопрос: если выбрать значение в первом селекте, а потом выбрать обратно пустое, то второй селект не возвращается в "disabled", как можно поправить этот недочет?

if (citySelect.find('option[value=0]').text() != 'Выберите область'){
    citySelect.removeAttr('disabled');
}

еще возник вопрос: можно ли как-то установить начальное значение для первого и второго селектов? Например, в первом: Московская область, во втором Москва...

либо при генерации html указать selected="selected", либо на клиенте выбрать с помощью js

Спасибо за скрипт! Но есть одна проблема, которую ни как не могу решить! Дело вот в чем: взял исходник, воткнул на сайт, проверил в Mozilla все работает. Открываю через IE, выбираю область, а он не подгружает города т.е. список городов остается disabled, в чем может быть причина? Это может быть из-за того, что не использовал файлик .htaccess? Заранее благодарю)

может

Решил прописать по другому как на сайте http://www.html.by/showthread.php?t=8789
Наверное у меня что, то с ajax запросами раз они не отображались в IE

Ковыряюсь с тройным селектом уже третий день (ничего не понимая в js)... Толь лыжи не едут, то ли я ... Помогли бы реализовать, хоть вектор указали б. Все чайники рунета поблагодарили б.

если нет необходимых знаний, пользуйтесь готовыми решениями

Огромная благодарность автору за прекрасную статью!!! Жаль что он не знает реализацию третьего селекта (или искуссно это скрывает), впрочем как и многие блогеры. Статья подтолкнула меня на изучение джавы. Научусь и тоже пальцы загну. :-)

Скажите, а как можно уведомлять пользователя когда идет загрузка?
Обычно это анимированная gif-картинка. Не могли бы вы показать на своём примере?
Спасибо.

смотрите исходники

Исходники я смотрел, данный пример, за который благодарен, прикрутил.
В нужном месте добавил div, в который будет грузиться gif-картинка.
<div id='loading'></div>
В js-код (после citySelect.html('');) добавил строку:

citySelect.html(''); // очищаем список городов
$('#loading').append(\"<img src='loader.gif' id='loader' />\");

Но нужно ведь еще таймер установить, время через которое будет отображаться результат, и очищаться div с картинкой. И вот тут я застрял, не понимаю, что нужно делать.

как то выборочно смотрели ;) вместо citySelect.attr('disabled', 'disabled'); показываете анимацию, вместо citySelect.removeAttr('disabled'); прячете. там даже комментарии есть

Я уже скрестил с другим подобным скриптом, там как раз анимация по таймеру. Но структура массива для списка городов, мне показалась сложной (каскадная вроде называется).
Так что оставил ваш пример, ничего не меняя, перед очищением списка городов добавил:

$('#city2').css('display','none');
$('#loading').append(\"<img src='loader.gif' style='float:left' id='loader' />\");
setTimeout(\"finishAjax()\", 500);
 
citySelect.html(''); // очищаем список городов

ну и функцию:
function finishAjax(){
  $('#loader').remove();
  $('#city2').css('display','block');
} 

От дива для картинки отказался. html:
<td id='loading'>Город:<br />
<select name='city' id='city2' disabled='disabled'><option>Выберите регион</option></select>
</td>

Получилось достаточно красиво! :)
Когда пользователь выбирает облать, поле с городами исчезает и вместо него появляется картинка-загрузка. По таймеру картинку прячем и показываем на этом месте поле с уже обновлённым списком городов.
Ух, я прям доволен результатом. :)

Пытаюсь сделать в Друпале 6.

Возник вопрос: у меня словарь с разной глубиной уровня вложенности.
Словарь предназначен для рубрик каталога.
Можете подсказать как сделать такое?
Третий день бьюсь над вашим кодом.

З.Ы. не пинайте в живот, я только учусь )))

С этим модулем я работал.
На форуме говорят, что от него невероятно растет размер базы.
Да и к тому же, он позволяет выбрать из словаря для конкретной типа ноды.
Мне же надо построить связь: Выбираем рубрику из словаря -> загружается новая нода.
Для каждой рубрики - свой тип ноды.

спасибо большое.

Когда выбираю обл. где городом появляется [object DOMWindow]
Подскажите пожалуйста, в чем проблема?

У меня кодировка cp1251, если альтернативный выход из ситуации?

Для тех у кого не работает с кодировкой ср1251, измените кусок кода:

<?php
// заполняем список областей
foreach ($city as $region => $cityList) {

echo '' . iconv('UTF-8', 'WINDOWS-1251', $region) . '' . "\n";
}
?>

            <?php
            // заполняем список областей
			foreach ($city as $region => $cityList) {
 
    				echo '<option value="' . iconv('UTF-8', 'WINDOWS-1251', $region) . '">' . iconv('UTF-8', 'WINDOWS-1251', $region) . '</option>' . "\n";
			}
            ?>

Когда выбираю обл. где городом появляется [object DOMWindow]

Такая же проблема, что делать? База в cp1251....

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

Сделал, как вы писали про :

if (citySelect.find('option[value=0]').text() != 'Выберите область'){
citySelect.removeAttr('disabled');
}

::::::

function(cityList){

citySelect.html(''); // очищаем список городов

// заполняем список городов новыми пришедшими данными
$.each(cityList, function(i){
citySelect.append('' + this + '');
});

if (citySelect.find('option[value=0]').text() != 'Выберите подкатегорию'){
citySelect.removeAttr('disabled'); // делаем список городов активным
}
});

Почему то не работает, не подскажите?

Тут писали : если выбрать значение в первом селекте, а потом выбрать обратно пустое, то второй селект не возвращается в "disabled"

И выбор во вторую select идет из базы, где pid = 0, то есть получется:

пусто | категория1

Оставить комментарий

Содержимое этого поля является приватным и не будет отображаться публично. Если у вас есть аккаунт в Gravatar, привязанный к этому e-mail адресу, то он будет использован для отображения аватара.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Доступные HTML теги: <a> <i> <b> <strong> <code> <ul> <ol> <li> <blockquote> <em> <s>
  • Строки и параграфы переносятся автоматически.
  • Подсветка кода осуществляется с помощью тегов: <code>, <css>, <html>, <ini>, <javascript>, <sql>, <php>. Поддерживаемые стили выделения кода: <foo>, [foo].

Подробнее о форматировании