Очень часто сталкиваюсь с вопросами реализации связанных динамичных выпадающих списков (select), очень много методов, самых различных, даже JSON в некоторых используется, что на мой скромный взгляд только дублирует данные из базы и создаёт банальную избыточность.
Однажды познакомился с $.ajax (JQuery), который может передавать данные методами GET или POST и понял, что связанные списки, это проще простого.
Ниже описан метод с использованием базы данных. Вся красота решения состоит в написании двух маленьких (похожих друг на друга) функций на JavaScript и одного исполняемого файла на PHP с кодом в 20 строк алгоритма переключения и генерации.
Нужно отметить, что есть методы, в которых можно генерировать динамические списки неограниченное количесво раз и все они будут связаны. В данной статье приводятся всего три списка, что, по-моему, достаточно для понимания метода как такового и создания на его основе улучшенных алгоритмов реализации задачи.
Постановка задачи: связать три (страна, область, город) выпадающих списка используя $.ajax (JQuery) без перезагрузки страницы, причём данные берутся из базы mySQL.
Реализация
Для начала создадим связанные таблицы в базе:
CREATE TABLE `tbl_country` ( `id_country` int(11) NOT NULL AUTO_INCREMENT, `country` varchar(32) NOT NULL, PRIMARY KEY (`id_country`), UNIQUE KEY `country` (`country`) ); INSERT INTO `tbl_country` VALUES(1, 'Украина'); INSERT INTO `tbl_country` VALUES(2, 'Россия'); INSERT INTO `tbl_country` VALUES(3, 'Белоруссия'); INSERT INTO `tbl_country` VALUES(4, 'Израиль'); CREATE TABLE `tbl_region` ( `id_region` int(11) NOT NULL AUTO_INCREMENT, `id_country` int(11) NOT NULL, `region` varchar(32) NOT NULL, PRIMARY KEY (`id_region`), UNIQUE KEY `region` (`region`), KEY `id_country` (`id_country`) ); INSERT INTO `tbl_region` VALUES(1, 1, 'АР Крым'); INSERT INTO `tbl_region` VALUES(2, 1, 'Винницкая обл.'); INSERT INTO `tbl_region` VALUES(3, 1, 'Днепропетровская обл.'); INSERT INTO `tbl_region` VALUES(4, 1, 'Донецкая обл.'); INSERT INTO `tbl_region` VALUES(5, 1, 'Житомирская обл.'); INSERT INTO `tbl_region` VALUES(6, 1, 'Закарпатская обл.'); INSERT INTO `tbl_region` VALUES(7, 1, 'Запорожская обл.'); INSERT INTO `tbl_region` VALUES(8, 1, 'Ивано-Франковская обл.'); INSERT INTO `tbl_region` VALUES(9, 1, 'Киевская обл.'); INSERT INTO `tbl_region` VALUES(10, 1, 'Кировоградская обл.'); INSERT INTO `tbl_region` VALUES(11, 1, 'Луганская обл.'); INSERT INTO `tbl_region` VALUES(12, 1, 'Волынская обл.'); INSERT INTO `tbl_region` VALUES(13, 1, 'Львовская обл.'); INSERT INTO `tbl_region` VALUES(14, 1, 'Николаевская обл.'); INSERT INTO `tbl_region` VALUES(15, 1, 'Одесская обл.'); INSERT INTO `tbl_region` VALUES(16, 1, 'Полтавская обл.'); INSERT INTO `tbl_region` VALUES(17, 1, 'Ровенская обл.'); INSERT INTO `tbl_region` VALUES(18, 1, 'Сумская обл.'); INSERT INTO `tbl_region` VALUES(19, 1, 'Тернопольская обл.'); INSERT INTO `tbl_region` VALUES(20, 1, 'Харьковская обл.'); INSERT INTO `tbl_region` VALUES(21, 1, 'Херсонская обл.'); INSERT INTO `tbl_region` VALUES(22, 1, 'Хмельницкая обл.'); INSERT INTO `tbl_region` VALUES(23, 1, 'Черкасская обл.'); INSERT INTO `tbl_region` VALUES(24, 1, 'Черниговская обл.'); INSERT INTO `tbl_region` VALUES(25, 1, 'Черновецкая обл.'); INSERT INTO `tbl_region` VALUES(27, 3, 'Минская обл.'); INSERT INTO `tbl_region` VALUES(28, 3, 'Брестская обл.'); INSERT INTO `tbl_region` VALUES(29, 3, 'Гомельская обл.'); INSERT INTO `tbl_region` VALUES(30, 3, 'Гродненская обл.'); INSERT INTO `tbl_region` VALUES(31, 3, 'Могилёвская обл.'); INSERT INTO `tbl_region` VALUES(32, 3, 'Витебская обл.'); INSERT INTO `tbl_region` VALUES(33, 4, 'Центральный округ'); INSERT INTO `tbl_region` VALUES(34, 4, 'Хайфский округ'); INSERT INTO `tbl_region` VALUES(35, 4, 'Северный округ'); INSERT INTO `tbl_region` VALUES(36, 4, 'Иерусалимский округ'); INSERT INTO `tbl_region` VALUES(37, 4, 'Южный округ'); INSERT INTO `tbl_region` VALUES(38, 4, 'Тель-Авивский округ'); INSERT INTO `tbl_region` VALUES(39, 4, 'Голанские высоты'); INSERT INTO `tbl_region` VALUES(40, 4, 'Западный берег'); INSERT INTO `tbl_region` VALUES(41, 4, 'Сектор Газа'); INSERT INTO `tbl_region` VALUES(42, 2, 'Адыгея'); INSERT INTO `tbl_region` VALUES(43, 2, 'Алтайский край'); INSERT INTO `tbl_region` VALUES(44, 2, 'Амурская обл.'); INSERT INTO `tbl_region` VALUES(45, 2, 'Архангельская обл.'); INSERT INTO `tbl_region` VALUES(46, 2, 'Астраханская обл.'); INSERT INTO `tbl_region` VALUES(47, 2, 'Башкортостан'); INSERT INTO `tbl_region` VALUES(48, 2, 'Белгородская обл.'); INSERT INTO `tbl_region` VALUES(49, 2, 'Брянская обл.'); INSERT INTO `tbl_region` VALUES(50, 2, 'Бурятия'); INSERT INTO `tbl_region` VALUES(51, 2, 'Владимирская обл.'); INSERT INTO `tbl_region` VALUES(52, 2, 'Волгоградская обл.'); INSERT INTO `tbl_region` VALUES(53, 2, 'Вологодская обл.'); INSERT INTO `tbl_region` VALUES(54, 2, 'Воронежская обл.'); INSERT INTO `tbl_region` VALUES(55, 2, 'Дагестан'); INSERT INTO `tbl_region` VALUES(56, 2, 'Еврейская АО'); INSERT INTO `tbl_region` VALUES(57, 2, 'Ивановская обл.'); INSERT INTO `tbl_region` VALUES(58, 2, 'Иркутская обл.'); INSERT INTO `tbl_region` VALUES(59, 2, 'Кабардино-Балкария'); INSERT INTO `tbl_region` VALUES(60, 2, 'Калининградская обл.'); INSERT INTO `tbl_region` VALUES(61, 2, 'Калмыкия'); INSERT INTO `tbl_region` VALUES(62, 2, 'Калужская обл.'); INSERT INTO `tbl_region` VALUES(63, 2, 'Камчатская обл.'); INSERT INTO `tbl_region` VALUES(64, 2, 'Карачаево-Черкессия'); INSERT INTO `tbl_region` VALUES(65, 2, 'Карелия'); INSERT INTO `tbl_region` VALUES(66, 2, 'Кемеровская обл.'); INSERT INTO `tbl_region` VALUES(67, 2, 'Кировская обл.'); INSERT INTO `tbl_region` VALUES(68, 2, 'Коми'); INSERT INTO `tbl_region` VALUES(69, 2, 'Корякский АО'); INSERT INTO `tbl_region` VALUES(70, 2, 'Костромская обл.'); INSERT INTO `tbl_region` VALUES(71, 2, 'Краснодарский край'); INSERT INTO `tbl_region` VALUES(72, 2, 'Красноярский край'); INSERT INTO `tbl_region` VALUES(73, 2, 'Курганская обл.'); INSERT INTO `tbl_region` VALUES(74, 2, 'Курская обл.'); INSERT INTO `tbl_region` VALUES(75, 2, 'Ленинградская обл.'); INSERT INTO `tbl_region` VALUES(76, 2, 'Липецкая обл.'); INSERT INTO `tbl_region` VALUES(77, 2, 'Магаданская обл.'); INSERT INTO `tbl_region` VALUES(78, 2, 'Марий Эл'); INSERT INTO `tbl_region` VALUES(79, 2, 'Мордовия'); INSERT INTO `tbl_region` VALUES(80, 2, 'Московская обл.'); INSERT INTO `tbl_region` VALUES(81, 2, 'Мурманская обл.'); INSERT INTO `tbl_region` VALUES(82, 2, 'Ненецкий АО'); INSERT INTO `tbl_region` VALUES(83, 2, 'Нижегородская обл.'); INSERT INTO `tbl_region` VALUES(84, 2, 'Новгородская обл.'); INSERT INTO `tbl_region` VALUES(85, 2, 'Новосибирская обл.'); INSERT INTO `tbl_region` VALUES(86, 2, 'Омская обл.'); INSERT INTO `tbl_region` VALUES(87, 2, 'Оренбургская обл.'); INSERT INTO `tbl_region` VALUES(88, 2, 'Орловская обл.'); INSERT INTO `tbl_region` VALUES(89, 2, 'Пензенская обл.'); INSERT INTO `tbl_region` VALUES(90, 2, 'Пермская обл.'); INSERT INTO `tbl_region` VALUES(91, 2, 'Приморский край'); INSERT INTO `tbl_region` VALUES(92, 2, 'Псковская обл.'); INSERT INTO `tbl_region` VALUES(93, 2, 'Республика Ингушетия'); INSERT INTO `tbl_region` VALUES(94, 2, 'Ростовская обл.'); INSERT INTO `tbl_region` VALUES(95, 2, 'Рязанская обл.'); INSERT INTO `tbl_region` VALUES(96, 2, 'Самарская обл.'); INSERT INTO `tbl_region` VALUES(97, 2, 'Саратовская обл.'); INSERT INTO `tbl_region` VALUES(98, 2, 'Саха (Якутия)'); INSERT INTO `tbl_region` VALUES(99, 2, 'Сахалинская обл.'); INSERT INTO `tbl_region` VALUES(100, 2, 'Свердловская обл.'); INSERT INTO `tbl_region` VALUES(101, 2, 'Северная Осетия'); INSERT INTO `tbl_region` VALUES(102, 2, 'Смоленская обл.'); INSERT INTO `tbl_region` VALUES(103, 2, 'Ставропольский край'); INSERT INTO `tbl_region` VALUES(104, 2, 'Таймырский АО'); INSERT INTO `tbl_region` VALUES(105, 2, 'Тамбовская обл.'); INSERT INTO `tbl_region` VALUES(106, 2, 'Татарстан'); INSERT INTO `tbl_region` VALUES(107, 2, 'Тверская обл.'); INSERT INTO `tbl_region` VALUES(108, 2, 'Томская обл.'); INSERT INTO `tbl_region` VALUES(109, 2, 'Тульская обл.'); INSERT INTO `tbl_region` VALUES(110, 2, 'Тыва'); INSERT INTO `tbl_region` VALUES(111, 2, 'Тюменская обл.'); INSERT INTO `tbl_region` VALUES(112, 2, 'Удмуртия'); INSERT INTO `tbl_region` VALUES(113, 2, 'Ульяновская обл.'); INSERT INTO `tbl_region` VALUES(114, 2, 'Хабаровский край'); INSERT INTO `tbl_region` VALUES(115, 2, 'Хакасия'); INSERT INTO `tbl_region` VALUES(116, 2, 'Ханты-Мансийский АО'); INSERT INTO `tbl_region` VALUES(117, 2, 'Челябинская обл.'); INSERT INTO `tbl_region` VALUES(118, 2, 'Чеченская Республика'); INSERT INTO `tbl_region` VALUES(119, 2, 'Читинская обл.'); INSERT INTO `tbl_region` VALUES(120, 2, 'Чувашия'); INSERT INTO `tbl_region` VALUES(121, 2, 'Чукотский АО'); INSERT INTO `tbl_region` VALUES(122, 2, 'Эвенкийский АО'); INSERT INTO `tbl_region` VALUES(123, 2, 'Ямало-Ненецкий АО'); INSERT INTO `tbl_region` VALUES(124, 2, 'Ярославская обл.'); CREATE TABLE `tbl_city` ( `id_city` int(11) NOT NULL AUTO_INCREMENT, `id_region` int(11) NOT NULL, `city` varchar(32) NOT NULL, PRIMARY KEY (`id_city`), UNIQUE KEY `city` (`city`), KEY `id_region` (`id_region`) ); INSERT INTO `tbl_city` VALUES(2, 4, 'Макеевка'); INSERT INTO `tbl_city` VALUES(6, 4, 'Енакиево'); INSERT INTO `tbl_city` VALUES(5, 4, 'Донецк');
Напишем следующий html код:
<select size="1" name="country" onchange="javascript:selectRegion();" style="float:left;"> <option value="">Все страны</option> <optgroup label="Выберите страну"> <option value="3">Белоруссия</option> <option value="4">Израиль</option> <option value="2">Россия</option> <option value="1">Украина</option> </optgroup> </select> <div name="selectDataRegion" style="float:left;"></div> <div name="selectDataCity" style="float:left;"></div>
Обратите внимание на 2 пустых дива «selectDataRegion» и «selectDataCity», в них мы будем вставлять сгенерированные выпадающие списки. Селект со странами сгенерирован с помощью запроса в базу с сортировкой по полю названия страны. Впринципе, если первый список у Вас статичный и данные неизменны, то можно просто написать данные в html и не использовать первую таблицу базы, но тогда прийдётся более внимательно относится к связке страны и value select соответственно.
Теперь напишем всего две функции JavaScript:
function selectRegion(){ var id_country = $('select[name="country"]').val(); if(!id_country){ $('div[name="selectDataRegion"]').html(''); $('div[name="selectDataCity"]').html(''); }else{ $.ajax({ type: "POST", url: "/action/ajax.base.php", data: { action: 'showRegionForInsert', id_country: id_country }, cache: false, success: function(responce){ $('div[name="selectDataRegion"]').html(responce); } }); }; }; function selectCity(){ var id_region = $('select[name="region"]').val(); $.ajax({ type: "POST", url: "/action/ajax.base.php", data: { action: 'showCityForInsert', id_region: id_region }, cache: false, success: function(responce){ $('div[name="selectDataCity"]').html(responce); } }); };
Обратите внимание, что в обеих функциях мы обращаемся к одному и тому же файлу. Красота пересылки данных методом POST позволяет создать переключатель switch по переменной action и правильно им воспользоваться.
Создадим файл исполнения /action/ajax.base.php:
<?php ini_set(default_charset,"UTF-8"); # include data base require "../../mysql.inc.php"; switch ($_POST['action']){ case "showRegionForInsert": echo '<select size="1" name="region" onchange="javascript:selectCity();">'; $rows = $DB->select('SELECT * FROM tbl_region WHERE id_country=? ORDER BY region ASC', $_POST['id_country']); foreach ($rows as $numRow => $row) { echo '<option value="'.$row['id_region'].'">'.$row['region'].'</option>'; }; echo '</select>'; break; case "showCityForInsert": echo '<select size="1" name="city">'; $rows = $DB->select('SELECT * FROM tbl_city WHERE id_region=? ORDER BY city ASC', $_POST['id_region']); foreach ($rows as $numRow => $row) { echo '<option value="'.$row['id_city'].'">'.$row['city'].'</option>'; }; echo '</select>'; break; }; ?>
Осталось теперь протестировать. Выберите «Украина» -> «Донецкая обл.» -> «Город» и будет Вам счастье! В качестве домашнего задания можно реализовать так: не скрывать списки областей и городов, а вместо пустых дивов показывать те же выпадающие списки, только прописать в них один нулевой параметр с тескстом выбора данных в раннем селекте или манипулировать параметром «disabled».