Динамический SELECT, динамические списки и база данных в MySQL

Построение зависимых html-списков, состав которых загружается из базы данных, а выбор значения влияет на соседние списки

Дата публикации: 20.06.2015

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

Если же ваши данные хранятся в таблице СУБД MySQL или какой-то иной, вам будет полезна информация из этой статьи. Я описываю алгоритм получения данных для раскрывающихся списков в HTML-теге SELECT с помощью JavaScript. Сам сценарий написан на PHP.

Если кому-то лень читать и хочется открыть книгу на последней странице, можно скачать все файлы в архиве.

Многим эта статья поможет написать дипломную или курсовую работу. Итак, техническое задание. Проект «Производители автомобилей и марки автомобилей».

Информация в этой статье для вас, скорее всего, сегодня уже является устаревшей. Вряд ли вы пытаетесь что-то «писать» для PHP версией старше чем 5.5. А если и пытаетесь… зачем оно вам? Среди материалов я уже разместил статью с построением динамических списков (динамических select-ов), работающих в трио с MySQL и PDO. Там работоспособный код. Смело переходите в ту статью.
  1. Cоздать HTML-форму, в которой можно выбрать производителя автомобиля и марку автомобилей выбранного производителя.
  2. Данные в списке моделей автомобилей должны быть уникальны для каждого производителя.
  3. Страница не должна перезагружаться после выбора производителя.

Задача ясна. Что мы можем добавить от себя? Если выбранный производитель меняется, значит из перечня моделей нужно удалить всё то, что имело отношение к предыдущему производителю. Если производитель не выбран, поле выбора модели должно быть пустым. А лучше сделать его еще и неактивным.

Начать нужно с таблиц в MySQL. Для того, чтобы решить задачу, нужно создать две таблицы в базе данных: producers (производители) и models (модели).


	
--
-- Структура таблицы `models`
--

CREATE TABLE IF NOT EXISTS `models` (
 `id` tinyint (2) NOT NULL,
 `producer_id` tinyint (3) NOT NULL,
 `model` char (64) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

-- --------------------------------------------------------

--
-- Структура таблицы `producers`
--

CREATE TABLE IF NOT EXISTS `producers` (
 `id` tinyint (2) NOT NULL,
 `producer` char (64) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

--
-- Индексы сохранённых таблиц
--

--
-- Индексы таблицы `models`
--
ALTER TABLE `models`
 ADD PRIMARY KEY (`id`);

--
-- Индексы таблицы `producers`
--
ALTER TABLE `producers`
 ADD PRIMARY KEY (`id`);

--
-- AUTO_INCREMENT для сохранённых таблиц
--

--
-- AUTO_INCREMENT для таблицы `models`
--
ALTER TABLE `models`
 MODIFY `id` tinyint (2) NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT для таблицы `producers`
--
ALTER TABLE `producers`
 MODIFY `id` tinyint (2) NOT NULL AUTO_INCREMENT;

Теперь пополним таблицы данными.


--
-- Дамп данных таблицы `producers`
--

INSERT INTO `producers` (`id`, `producer`) VALUES
 (1, 'KIA'),
 (2, 'Hyundai'),
 (3, 'Lada'),
 (4, 'Chevrolet'),
 (5, 'Opel');

--
-- Дамп данных таблицы `models`
--

INSERT INTO `models` (`id`, `producer_id`, `model`) VALUES
 (1, 1, 'Cerato'),
 (2, 1, 'Ceed'),
 (3, 1, 'Picanto'),
 (4, 1, 'Optima'),
 (5, 2, 'Accent'),
 (6, 2, 'Santa Fe'),
 (7, 2, 'IX35'),
 (8, 2, 'Solaris'),
 (9, 1, 'Rio'),
 (10, 2, 'Getz'),
 (11, 3, 'Granta'),
 (12, 3, 'Priora'),
 (13, 3, 'Kalina'),
 (14, 3, 'Samara'),
 (15, 3, '4x4'),
 (16, 4, 'Aveo'),
 (17, 4, 'Lacetti'),
 (18, 4, 'Cobalt'),
 (19, 4, 'Cruze'),
 (20, 4, 'Captiva'),
 (26, 5, 'Vectra'),
 (27, 5, 'Mokka'),
 (28, 5, 'Astra'),
 (29, 5, 'Corsa');


Чтобы подключаться к нашей базе данных мы будем использовать уже знакомый вам сценарий подключения к СУБД.

Теперь можно создать HTML-форму. Сразу скажу, что здесь у нас будут работать в связке PHP, MySQL и jQuery. Именно с помощью jQuery select с перечнем моделей автомобилей будет получать данные из базы данных (динамические списки, так сказать).


<?php
// Подключаем файл для соединения с СУБД MySQL
require_once ('database.php') ;
// Подключаем файл, в котором будем объявлять пользовательские функции
require_once ('functions.php') ;
?>
<!-- Пишем в рамках стандарта HTML5 →
<!DOCTYPE html>
<html>
<head>
	<title>Выбор марки и модели автомобиля</title>
	<!-- Подключаем библиотеку jQuery →
	<script src=»//libs.raltek.ru/libs/jquery/1.8.3/js/jquery-1.8.3.js»></script>
	<!-- Подключаем таблицу стилей →
	<link href= «style.css» rel= «stylesheet» type= «text/css» />
	<!-- Подключаем JavaScript-файл с нашим сценарием, который и будет получать данные об автомобилях →
	<script src= «scripts.js»></script>
</head>
<body>
	<!-- Создаем контейнер-обертку для нашей формы →
	<div id= «car_producers_wrapper»>
		<!-- Сама форма →
		<form name= «car_producers» id= «car_producers» >
			<!-- Контейнер для поля выбора производителя →
			<div class= «row»>
				<!-- Метка поля производителей автомобилей →
				<label for= «producer»>Производитель автомобилей:</label>
				<!-- Раскрывающийся список производителей автомобилей →
				<select id= «producer»>
					<option value= «0»>Выберите из списка</option>
					<?php					
					// Получаем перечень производителей в виде массива
					$aProducers = getProducers ();
					
					// Для каждого элемента массива производителей автомобилей…
					foreach ($aProducers as $aProducer) {
						// Создаем свой элемент раскрывающегося списка
						print '<option value=»'. $aProducer[ 'id' ]. '">'. $aProducer[ 'producer' ]. '</option>';
						
					}
					?>
				</select>
			</div>
			<!-- Контейнер для поля выбора модели автомобиля выбранного производителя →
			<div class= «row»>
				<!-- Метка поля выбора марки автомобиля →
				<label for= «model»>Марка автомобиля:</label>
				<!-- Раскрывающийся список выбора марки автомобиля выбранного производителя →
				<!-- Изначально список пуст и неактивен →
				<!-- Данные в нем появятся полсле выбора производителя →
				<select id= «model» disabled >
					<option value= «0»>Выберите из списка</option>
				</select>
			</div>
			
		</form>
	</div>
</body>
</html>

Если вы внимательно просмотрите код, заметите в нем ранее нигде не объявленную функцию getModels (). В самом начале кода для файла HTML-формы мы подключили два внешних файла: database.php (для подключения к СУБД) и functions.php (для объявления пользовательских функций). Вот во втором файле и была объявлена функция getModels (). Код самого файла я приведу ниже. А упомянутая функция просто получает из базы данных MySQL перечень производителей автомобилей.

Теперь нашей форме нужно придать какой-нибудь простенький внешний вид. Для этого мы создадим очень небольшой CSS-файл со стилями.


/**
 * Просто внешний вид */
body {
	font-size:12pt;
	color:#333333;
	font-family: Tahoma, Verdana, Arial, Sans-Serif;
}
.row {
	margin-bottom:10px;
}
.row label {
	margin-bottom:5px;
	font-weight:bold;
	width:280px;
	display:block;
}
.row select {
	width:300px;
	font-size:1.1em;
	border:1px solid #aaaaaa;
	padding:3px 5px;
}
#car_producers_wrapper {
	width: 310px;
	margin: 100px auto 0 auto;
}

После этого наша форма будет выглядеть примерно вот так:

Приведу код содержимого файлаfunctions.php. Комментарии внутри файла достаточны. Думаю, более ничего дописывать нет необходимости.


<?php
/**
 * Функция для получения перечня производителей автомобилей
 */
function getProducers () {
	
	// Подключаемся к СУБД MySQL
	connect ();
	
	// Выбираем всех производителей из таблицы
	$sql = «SELECT * FROM `producers` ORDER BY `producer`»;
	
	// Выполняем запрос
	$query = mysql_query ($sql) or die (mysql_error ()) ;
	
	// Поместим данные, которые будет возвращать функция, в массив
	// Пока что он будет пустым
	$array = array ();
	
	// Инициализируем счетчик
	$i = 0;
	
	while ($row = mysql_fetch_assoc ($query)) {
		
		$array[ $i ][ 'id' ] = $row[ 'id' ];				// Идентификатор производителя
		$array[ $i ][ 'producer' ] = $row[ 'producer' ];	// Имя производителя
		
		// После каждой итерации цикла увеличиваем счетчик
		$i++;
		
	}
	
	// Возвращаем вызову функции массив с данными
	return $array;
	
}

// Функция, которая выбирает модели автомодилей по переданному
// ей идентификатору производителя
function getModels (array $array) {
	
	// Сохраняем идентификатор производителя из переданного массива
	$sProducerId = htmlspecialchars (trim ($array[ 'producer_id' ])) ;
	
	// Подключаемся к MySQL
	connect ();
	
	// Строка запроса из базы данных
	$sql = "SELECT `id`, `model` FROM `models` WHERE `producer_id` = '". $sProducerId. "' ORDER BY `model`";
	
	// Выполняем запрос
	$query = mysql_query ($sql) or die (mysql_error ()) ;
	
	// Поместим данные, которые будет возвращать функция, в массив
	// Пока что он будет пустым
	$array = array ();
	
	// Инициализируем счетчик
	$i = 0;
	
	while ($row = mysql_fetch_assoc ($query)) {
		
		$array[ $i ][ 'id' ] = $row[ 'id' ];		// Идентификатор модели
		$array[ $i ][ 'model' ] = $row[ 'model' ];	// Наименование модели
		
		// После каждой итерации цикла увеличиваем счетчик
		$i++;
		
	}
	
	// Возвращаем вызову функции массив с данными
	return $array;
	
}
?>

Итак, у нас есть два раскрывающихся списка. В одном из них производители автомобилей, в другом — модели автомобилей. Списки зависимы. Списокselect#modelзависит от выбора в спискеselect#producer. Содержимое списка производителей у нас уже есть. Его нам обеспечил сам сервер. А вот чтобы получить содержимое списка моделей, да еще и зависящее от выбранного производителя, придется потрудиться JavaScript-у. Весь наш пользовательский JavaScript-сценарий помещен в файлscripts.js.

Именно в этом файле написан обработчик события выбора производителя, после которого создается AJAX-запрос к веб-серверу, способный вернуть в ответ перечень моделей автомобиля выбранного производителя.


 (function ($) {
	
	// Включаем строгий режим ECMA-Script
 «use strict»;
	
	/**
	 * В скрипте мы будем выполнять AJAX-запросы к СУБД MySQL
	 * Чтобы каждый раз не писать один и тот же код AJAX-запроса, создадим 
	 * свой метод request в объекте jQuery
	 */
	$.extend ({
		request: function (options) {
			
			// В методе request будут различные опции (настройки)
			// Это своего рода настройки по умолчанию, созданные
			// в объекте options
			options = $.extend ({
				
				type: «POST»,					// Метод передачи данных серверу
				url: «requests.php»,			// Путь к файлу со сценарием обращения к СУБД
				data: null,						// Данные, которые мы будем передавать серверу
				async: false,					// Асинхронность выполнения AJAX-запроса
				dataType: «json»,				// Тип данных, в котором они передаются
				before: null,					// Код, выполняемый перед AJAX-запросом
				error: function () {},			// Код, выполняемый в случае какой-либо ошибки при AJAX-запросе
				complete: options.callback,		// Код, выполняемый после AJAX-запроса	
				success: function (result) {	// Код, выполняемый после получения ответа от сервера
					$.response.result = result;	// Помещаем ответ от сервера в отдельный объект
				},
				result: null,					// Результат работы
				callback: null					// Функция обратного вызова
				
			}, options) ;
			
			// Тело AJAX-запроса
			$.ajax ({
				
				type: options.type,
				url: options.url,
				data: options.data,
				async: options.async,
				dataType: options.dataType,
				before: options.before,
				error: options.error,
				complete: options.complete,
				success: options.success
				
			});
			
			return this;
			
		},
		// Объект, в котором хранится ответ от сервера, полученный через AJAX-запрос
		response: {
			result: {}
		}
	});
	
	jQuery (function () {
		
		/**
		 * При выборе производителя нужно сделать многое
		 * Сначала из списка моделей должны быть удалены все имеющиеся модели автомобилей
		 * Затем поле выбора модели автомобиля должно стать неактивным
		 */
		 
		// Обработчик события выбора производителя
		$ ('#producer'). change (function () {
			
			var producer_id = $ (this). val ();	// Идентификатор выбранного производителя
			
			
			
			// Отключаем поле, установив значения свойства disabled
			$ ('#model'). prop ('disabled', true) 
			
			// Находим и удаляем все возможные модели автомобилей из раскрывающегося списка
			.find ('option:not (:first) '). remove ();
			
			
			
			// Если был выбран конкретный производитель
			if (producer_id! = 0) {
				
				// Создаем AJAX-запрос, который вернет нам перечень моделей для выбранной марки 
				$.request ({
					
					data: «request=getModels&producer_id=» + producer_id,
					
				});
				// Успешный AJAX-запрос должен закончиться вставкой полученного перечня моделей 
				// в раскрывающийся список select#model
				// Результат AJAX-запроса мы сохраняли в отдельном объекте
				var i = 0, models = $.response.result;
				for (i; i < models.length; i++) {
					
					$ ('#model'). append ('<option value=»' + models[ i ].id + '">' + models[ i ].model + '</option>') ;
					
				}
				
				// Включаем поле со списком моделей
				$ ('#model'). prop ('disabled', false) ;
				
			}
			
		}); // Обработчик события выбора производителя
	
	});
	
}) (jQuery); // Используем немедленно вызываемую анонимную функцию

Если вы внимательно просмотрите код JavaScript, увидите, что AJAX-запросы будут отправляться файлуrequests.php. Этот файл обратно в ответ на запрос будет отправлять данные. Если говорить конкретно — перечень моделей автомобилей в ответ на выбор производителя машин. Привожу его код.


<?php
// Подключаем файл для соединения с СУБД MySQL
require_once ('database.php') ;
// Подключаем файл, в котором будем объявлять пользовательские функции
require_once ('functions.php') ;

/**
 * Данные передаются методом POST
 * Если массив POST, пустой, что-то идет не так * Более того, переменная $_POST[ 'request' ] пустая, или её не существует,
 * значит тоже что-то не так */
if (empty ($_POST)) {
	
	die ("Массив \$_POST пустой") ;
	
}
elseif (empty ($_POST[ 'request' ])) {
	
	die ("Не передан запрос") ;
	
}
else {
	
	// Очищаем строку с типом запроса от лишних пробелов и защищаемся от возможных SQL-инъекций
	$request = htmlspecialchars (trim ($_POST[ 'request' ])) ;
	
	// Убираем тип запроса из массива $_POST
	unset ($_POST[ 'request' ]) ;
	
}

// В переменной $response будем возвращать данные AJAX-запросу
$response = NULL;

switch ($request) {
	case «getModels»:
		
		$response = getModels ($_POST) ;
		
	break;
}

echo json_encode ($response) ;
?>

Вот и всё. Задача решена. Можно выбрать производителя.

После этого можно выбрать модель автомобиля.

Можно сменить производителя. Тогда содержимое списка моделей очистится и обновится новым перечнем.

А можно вообще ничего не выбрать среди производителей. Тогда список моделей сбросится, а потом отключится.

Все файлы, упомянутые в статье, я поместил в архив.

Информация в этой статье для вас, скорее всего, сегодня уже является устаревшей. Вряд ли вы пытаетесь что-то «писать» для PHP версией старше чем 5.5. А если и пытаетесь… зачем оно вам? Среди материалов я уже разместил статью с построением динамических списков (динамических select-ов), работающих в трио с MySQL и PDO. Там работоспособный код. Смело переходите в ту статью.
  • Я опубликовал эту статью:20.06.2015
  • 43 644
  • Яндекс.Метрика

Меню сайта

Settings

Performance

CPU Load
60%
CPU Temparature
42°
RAM Usage
6,532 MB

Customer care

Reports

Projects

May 14, 2020

Upcoming events

12:00

Donec laoreet fringilla justo a pellentesque

13:20

Nunc quis massa nec enim

14:00

Praesent sit amet