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

24.12.2009

Зависимые списки — это два и более 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).

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

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

Комментарии

Гость
03.03.2010, 00:23

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

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

Гость
03.03.2010, 01:24

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

вам не обязательно иметь формат массива как у меня в файле 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>
Гость
03.03.2010, 13:35

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

в том месте где обрабатываете 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'"); - мне кажется тоже не вариант... :)

Гость
27.09.2010, 14:42

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

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

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

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

Гость
15.10.2010, 09:14

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

Гость
01.03.2011, 18:46

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

Гость
02.03.2011, 13:00

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

Сергей
12.07.2011, 07:41

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

Сергей
12.07.2011, 21:56

Исходники я смотрел, данный пример, за который благодарен, прикрутил.
В нужном месте добавил 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'); прячете. там даже комментарии есть

Сергей
12.07.2011, 23:21

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

$('#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";
			}
            ?>
Гость
19.10.2011, 21:40

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

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

Гость
25.10.2011, 23:04

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

Гость
30.12.2011, 15:21

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

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'); // делаем список городов активным
}
});

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

Гость
30.12.2011, 15:30

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

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

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

Гость
04.03.2012, 13:25

Подскажите, если я знаю город пользователя, как его сразу выбрать, чтоб и регион сразу был верный?

Гость
14.04.2012, 13:22

Добрый день xandeadx! урок получился, только один небольшой нюанс, когда выбираешь выбираешь 0 элемент то в списке городе пишется Object Window, подскажи где копать? думал добавим примерно такой код решится, увы нет... жду вашего отклика. сапсибо заранееif (regionSelect.selectedIndex == 0) citySelect.attr('disabled');

Гость
08.05.2012, 03:25

у меня при выборе города, в базу вводится не название города, а цифра, которая ему присвоенная... что я не так сделал? я в этом деле новичок...

Александр
08.05.2012, 20:28

Как это к фильтам views прицепить(или сделать вместо них)? Все сделал, кнопка выводит данные в url (get прописал), но проблема в том, что если фильтрация по этим параметрам, которые я прописал, отключена в views, то и у меня не работает. Что делать? Может в коде views покапаться? Заранее благодарен!

Гость
15.05.2012, 06:15

Ага, подскажите, пожалуста, как подобную шнягу прикрутить к фильтрам для 7 друпала, а если точнее, то как все это соединить в рабочем фильтре хоть с помощью hierarchical Select, хоть с помощью Conditional Fields?
Ибо ни тот ни другой модуль со вьюхами работать не хочет...

Александр
15.05.2012, 09:07

Гость, который, как и я про views интересуется. Я нашел как прицепить это к views, только чуть-чуть другим способом, отпишите на почту мне, объясню. (petrovforz44@gmail.com)

Гость
28.05.2012, 06:32

Здравствуйте!
У меня вот такая вот задача: реализовать такую структуру:
выводиться первый список, где выбирается номер квартиры, при выборе определенной квартиры во втором списке высвечиваются все ее жители и на страничке вместе с этим выводиться информация о квартире(площадь, номер дома этажа и т.п.), а когда выбираешь во втором выпадающем списке определенного жильца появляется подробная информация о нем.

Информация о квартире и жильцах храниться в БД mysql в 2х таблицах:

табл квартиры:
id_kv____etag____kolvo_komnat ...
1________1_______2
2________4_______3
..._______...______...

табл жильцы
id_people____ id_kv____ last_name___name ...
1 ___________1_______...
2 ___________1_______
3 ___________1_______
4 ___________2_______
5 ___________2_______
... __________..._______

Помогите плиз, реализовать, очень срочно надо, в инете кучу всего пересмотрел, только запутался....

Гость
06.06.2012, 14:16

Приветик всем!
Мучаюсь с подобными выпадающими списками на Drupal 7.
hierarchical_select со Views в Drupal 7 работать упорно не желает. Попытался замутить с Conditional Fields в совокупности с Views Dependent Filters. Вроде как получилось, но не так чтобы хотелось.
Дело в том, что при создании ноды работа Conditional Fields вполне устраивает, а вот при отображении фильтров поиска во Views 3 требуется сделать так, чтобы при начальной установке значений фильтров и при возвращенни к опции "Выбрать все" первый зависимый фильтр не просто был скрывался от показа посредством придания свойства div в обвертке фильтра как display: none , а отображался, но с опцией не для обвертки div, а для самого элемента select с опцией disabled="disabled".
Не подскажете что лучше с этим сделать, может дополнительный javascript, который будет перезаписывать результаты?

Станислав
11.06.2012, 00:05

Попытался, возможно нерационально, но как умею, решить задачу приведенную выше, но не совсем получилось.
Итак, имеем в Drupal 7 один список стран (field_region_value) и четыре списка зависимых от страны городов (field_region_1_value, field_region_2_value и т.д.) в виде блока раскрытых фильтров.
Подключаем следующий код к нашему сайту:

(function ($) {
  Drupal.behaviors.tb_neris = {
    attach: function (context, settings) { 	
	$('form#views-exposed-form-town-select-page').jqTransform({imgPath:'/images/'}); // Подключаем jqTransform плагин	
	$('.jqTransformSelectWrapper ul li a', context).bind('click', function() { // Ожидаем клика в любом выпадающем списке
		Drupal.attachBehaviors(this); // Пересчитывам данные в зависимости от клика в списке с учетом зависимостей заданных в других модулях		
		});
			if ($('select[name=field_region_value] option:selected').val() == 'All'){ // Проверяем выбрана ли конкретная страна, если нет, то
			$('div.views-widget-filter-field_region_1_value').css('display','block'); // Принудительно показываем скрытую форму для 1-го списка городов (обход особенности модуля скрывать все зависимые формы)
			$('select[name=field_region_1_value]').val('All'); // Устанавливаем принудительно значение All для 1-го списка городов
			$('select[name=field_region_1_value]').attr('disabled',true); // отключаем возможность что-либо изменить в форме
			}else{ // иначе если страна определена, то
			$('select[name=field_region_1_value]').attr('disabled',false);	// даем возможность модулю зависимостей делать свою работу		
			}
	}
  };
})(jQuery);

Подскажите пожалуйста, почему значение первого списка городов field_region_1_value в форме переделанной jqTransform не возвращается в исходное положение val='All' когда явно не выбрана страна для field_region_value как val='All', хотя форма работает правильно, и после клика по кнопочке "Поиск" устанавливает значение 'All' как и хотелось?

Александр
19.06.2012, 10:05

Примерно 3 месяца назад мучался с такой же проблемой динамически выпадающих списков. Могу сказать одно, если создаешь сайт, т о сам должен создать такой скрипт для своего проекта. Поверьте, крайне легко он создается. Причем делать нужно его с помощью Query. И ни каких проблем с кодировкой. Можно делать тройные, десятерные списки. И немножко PHP нужно знать. Поэтому, господа, помучавшись с кодом, отправляйтесь учить Query и чуть-чуть JS, При нормальном процессе через месяц, будете создавать скрипты, не хуже этого. Кстати, автор предлагает не самое верное и легкое решение этого вопроса

Гость
17.09.2012, 15:48

Здравствуйте ! Во-первых, спасибо за отличную статью! Оч полезно. У меня вот какой вопрос. Всё это реализовать у меня удалось, отдельно. Только начал вставлять в конкретный сайт - не работает. Делаю всё то же самое. Проблема - не появляются области, не из чего выбирать. Посмотрел исходный код, на месте областей пишет:

b>Warning: Invalid argument supplied for foreach() in /home/s/ru/public_html/1/add-1/add-1-step-1-new.php on line 657<

Помогите пожалуйста решить проблему. Уже голову поломал

Гость
11.10.2012, 06:34

Как получить то вместо цифр районов их названия?

Антон
05.01.2013, 23:45

Как получить то вместо цифр городов их названия?

Какой файл в Drupalе надо править, чтобы зависимые списки создавать? Или это мод какой-то писать/скачивать нужно? Что за мод в таком случае? А то реализация кода примерно понятна, но куда его вставлять - нет.

Гость
28.02.2013, 12:28

Привет всем любое время суток!
Скажите пожалуйста! Не совсем понял, а как это все применить для Drupal 7, и сделать так чтобы отправляло после выбора на определенную страницу?
За ранее спасибо за ответ!

Гость
15.04.2013, 11:35

Здравствуйте. Подскажите пожалуйста как мне получить значение ключа...
echo $_POST['city'] ;
echo "";
echo $_POST['region'] ;
echo "";
echo $_POST['cityList'] ;
даёт просто название региона и цифру

Гость
19.04.2013, 12:35

Спасибо за статью, а как можно сделать что бы на одной странице html было два таких списка как вы представили?

Обычно редактирую php-файлы в обычном текстовом редакторе Bred3r
а каким редактором едактировать файлы из примера?
Спасибо заранее

webberloga.com
10.06.2013, 22:51

Спасибо большое, время поджимало благодоря вам успел закончить.

Никита
22.09.2013, 01:16

Ребят, помогите пожалуйста. Часа три просидел над кодом, ни чего не смог придумать. ПРоблема - взял код с http://pastebin.com/sP7gGbe2 и сделал под себя. Но смысл в том что у меня после выбора первого ( области ) вместо города пишется [object window]. И не хочет давать мне $_GET['region']. Если нужно, то я код кину полностью. В заранее спасибо

Гость
01.10.2013, 11:58

я написал свой скрипт зависимых списков, но теперь проблема с которой не могу разобраться: списки используются в фильтре, и после отбора обнуляются - как сделать чтобы не обнулялись если все значения формируются динамически по аякс?

Гость
08.07.2014, 02:00

Если делать данный скрипт для вывода информации о городе на той же странице, что и сам скрипт, то после нажатия кнопки теряется выбранный город. Поле становится серым, неактивным и предлагает выбрать город. А чтобы его выбрать, нужно сначала выбрать другой регион, потом правильный регион и выбрать город. Передается все из формы правильно, но как сохранить для пользователя его выбор города? Сохранить регион не сложно при помощи РНР манипуляций. Но город грузятся по запросу, и если на странице произошел POST запрос, то сбрасывается настройка JS фильтра на регион, точнее города исчезают, тем более исчезает выбранный. Это реально исправить? Т.е. добавить "selected" для города?

Алексей
13.08.2014, 16:27

Люди добрые, напишите, пожалуйста, вариант кода для работы с БД drupal 7 (таксономия).

Потребитель
23.09.2014, 08:28
// послыаем AJAX запрос, который вернёт список городов для выбранной области
    $.getJSON('index.php', {action:'getCity', region:select.value}, function(cityList){

Как быть, если код встраивается на в index.php? Он вызывается на, допустим, /sf?city=ku$years=28

Что прописывать вместо index.php?

Анатолий
05.04.2015, 21:09

Спасибо автору за статью.
Успешно установил код на сайт. После замены кодировки на UTF-8 стал доступен выбор во втором select.
Так же как и некоторые из оставивших комментарии, толкнулся с проблемой передачи значений второго select. Вместо названий городов получаю только порядковый номер города.
Подскажите пожалуйста как получать названия городов для дальнейшей работы.

Заранее спасибо!
Анатолий
Анатолий

Анатолий
05.04.2015, 22:48

Решил проблему средствами php через обращение к БД, используя цикл и условие проверки, но все же было бы интересно узнать от автора как передавать через POST название города а не его порядковый номер.

Заранее спасибо.

Нодир
18.12.2015, 14:52

Добрый день!
у меня бронирования билетов..сеансы и цены разные когда клиент выбирает нужный сеанс цена должен появиться который выбрал клиент...можете помочь ?
(Спасибо заранее)

Гость
17.06.2017, 13:28

Здравствуйте. Извиняюсь за глупый вопрос, как вывести форму с данными зависимыми списками. Спасибо

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

Добавить комментарий