Пусть у нас есть Интернет-магазин и мы хотим предоставить покупателю удобный интерфейс выбора товара. Для этого мы формируем три выпадающих списка для выбора:
- Категории (группы) товаров, например “Мониторы”, “Ноутбуки” и т.п.
- Производителя, например, “Samsung”, “Acer” и т.п.
- Товара
Вопрос в том, что эти выпадающие списки зависят друг от друга. Если пользователь выбрал категорию “Мониторы”, то мы должны сформировать второй список таким образом, чтобы в нем были представлены только производители мониторов. Соответственно, третий список формируется на основе выбранных значений первого и второго списков.
Для начала рассмотрим структуру базы данных нашего магазина.
Таблица categories:
Таблица makers:
Таблица products:
Имея перед глазами эти три таблицы, нетрудно прикинуть, как будут выглядеть наши выпадающие списки:
1=>Мониторы
1001=>Samsung
1=>Монитор Samsung 740N
2=>Монитор Samsung 943N
3=>Монитор Samsung 2043NW
4=>Монитор Samsung SM2232BW
1002=>Acer
5=>Монитор Acer AL1716FS
6=>Монитор Acer AL1916CS
7=>Монитор Acer AL2216WSD
8=>Монитор Acer AL2416WBSD
1004=>BenQ
15=>Монитор BenQ G900W
16=>Монитор BenQ G700
2=>Ноутбуки
1001=>Samsung
11=>Ноутбук Samsung R20
12=>Ноутбук Samsung R60
1002=>Acer
9=>Ноутбук Acer Aspire 5315
10=>Ноутбук Acer Extensa 5220
1003=>Toshiba
13=>Ноутбук Toshiba A210-19A
14=>Ноутбук Toshiba A210-199
Ну а дальше - реализация нашей идеи:
Файл index.php
<?php
// Соединяемся с сервером базы данных
require 'connect.php';
header("Content-Type: text/html; charset=utf-8");
?>
<html>
<head>
<title>Динамический select</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript" src="ajax.js"> </script>
</head>
<body>
<?php
echo '<form action="'.$_SERVER['PHP_SELF'].'" method="post">'."\n";
// Получаем из БД список категорий
$query = 'SELECT category_id, title FROM categories WHERE 1 ORDER BY category_id';
$res = mysql_query( $query );
echo 'Категории: <select name="category" id="category" onchange="getList(this.value, \'\');">'."\n";
echo '<option value="0">Выберите</option>'."\n";
while ( $ctg = mysql_fetch_array( $res ) ) {
echo '<option value="'.$ctg['category_id'].'">'.$ctg['title'].'</option>'."\n";
}
echo '</select><br/>'."\n";
?>
Производители:
<select name="maker" id="maker" onchange="getList(this.form.elements['category'].value, this.value);">
<option value="0">Выберите</option>
</select><br/>
Товары: <select name="product" id="product"><option value="0">Выберите</option></select>
</form>
</body>
</html>
Файл getList.php
<?php
// Соединяемся с сервером базы данных
require 'connect.php';
// Если выбрано значение первого списка - формируем второй список
if ( !isset($_GET['maker']) ) {
// Получаем из БД список производителей
$query = 'SELECT DISTINCT a.maker_id AS m_id, a.title AS m_title
FROM makers a INNER JOIN products b
ON a.maker_id=b.maker_id
WHERE b.category_id='.$_GET['category'].'
ORDER BY a.maker_id';
$res = mysql_query( $query );
$makerOptions = '<option value="0">Выберите</option>';
while ( $mkr = mysql_fetch_array( $res ) ) {
$makerOptions = $makerOptions.'<option value="'.$mkr['m_id'].'">'.$mkr['m_title'].'</option>';
}
$response = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'.
'<response>'.
'<action>'.
'makeMakerList'.
'</action>'.
'<options>'.
$makerOptions.
'</options>'.
'</response>';
} else { // Если выбрано значение из списка производителей - формируем список товаров
$query = 'SELECT product_id, title
FROM products
WHERE category_id='.$_GET['category'].'
AND maker_id='.$_GET['maker'].'
ORDER BY product_id';
$res = mysql_query( $query );
$productOptions = '<option value="0">Выберите</option>';
while( $prd = mysql_fetch_array( $res ) ) {
$productOptions = $productOptions.'<option value="'.$prd['product_id'].'">'.$prd['title'].'</option>';
}
$response = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'.
'<response>'.
'<action>'.
'makeProductList'.
'</action>'.
'<options>'.
$productOptions.
'</options>'.
'</response>';
}
header('Content-Type: text/xml');
echo $response;
?>
Файл ajax.js
var request = null;
function createRequest() {
try {
request = new XMLHttpRequest();
} catch (trymicrosoft) {
try {
request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (othermicrosoft) {
try {
request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (failed) {
request = null;
}
}
}
if (request == null) alert("Ошибка при создании объекта XMLHttpRequest!");
}
function getList(ctg, mkr) {
document.getElementById("product").innerHTML = '<option value="0">Выберите</option>';
if ( mkr == "" )
url = "getList.php?category=" + ctg;
else
url = "getList.php?category=" + ctg + "&maker=" + mkr;
createRequest();
request.open("GET", url, true);
request.onreadystatechange = makeList;
request.send(null);
}
function makeList() {
// только при состоянии "complete"
if (request.readyState == 4) {
// для статуса "OK"
if (request.status == 200) {
// здесь идут построение списков заново
responseXml = request.responseXML;
xmlDoc = responseXml.documentElement;
action = xmlDoc.getElementsByTagName("action")[0].firstChild.data;
options = xmlDoc.getElementsByTagName("options")[0].firstChild.data;
if ( action == "makeMakerList" )
document.getElementById("maker").innerHTML = options;
else
document.getElementById("product").innerHTML = options;
} else {
alert("Не удалось получить данные от сервера:\n" + request.statusText);
}
}
}
var request = null;
function createRequest() {
try {
request = new XMLHttpRequest();
} catch (trymicrosoft) {
try {
request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (othermicrosoft) {
try {
request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (failed) {
request = null;
}
}
}
if (request == null) alert("Ошибка при создании объекта XMLHttpRequest!");
}
function getList(ctg, mkr) {
var _select = document.getElementById("product");
_select.innerHTML = ""; // Удаляем всех потомков
var option = document.createElement("option");
var optionText = document.createTextNode("Выберите");
option.appendChild(optionText);
option.setAttribute("value", "0");
_select.appendChild(option);
if ( mkr == "" )
url = "getList.php?category=" + ctg;
else
url = "getList.php?category=" + ctg + "&maker=" + mkr;
createRequest();
request.open("GET", url, true);
request.onreadystatechange = makeList;
request.send(null);
}
function makeList() {
// только при состоянии "complete"
if (request.readyState == 4) {
// для статуса "OK"
if (request.status == 200) {
// здесь идет построение списков заново
var responseXml = request.responseXML;
var xmlDoc = responseXml.documentElement;
var action = xmlDoc.getElementsByTagName("action")[0].firstChild.data;
if ( action == "makeMakerList" ) {
_select = document.getElementById("maker");
} else {
_select = document.getElementById("product");
}
_select.innerHTML = ""; // Удаляем всех потомков
options = xmlDoc.getElementsByTagName("option");
for (var i=0; i<options.length; i++) {
// Извлекаем значение атрибута value и текст
var value = options[i].getAttribute("value");
var text = options[i].firstChild.data;
// Формируем очередной элемент option
var option = document.createElement("option");
var optionText = document.createTextNode(text);
option.appendChild(optionText);
option.setAttribute("value", value);
_select.appendChild(option);
}
} else {
alert("Не удалось получить данные от сервера:\n" + request.statusText);
}
}
}
Дамп базы данных:
CREATE TABLE `products` (
`product_id` INT(11) NOT NULL AUTO_INCREMENT,
`category_id` INT(11) NOT NULL DEFAULT '0',
`maker_id` INT(11) NOT NULL DEFAULT '0',
`title` VARCHAR(255) NOT NULL DEFAULT '',
`price` FLOAT NOT NULL DEFAULT '0',
PRIMARY KEY (`product_id`)
) ENGINE=INNODB DEFAULT CHARSET=cp1251;
INSERT INTO `products` VALUES (1, 1, 1001, 'Монитор Samsung 740N', 5700);
INSERT INTO `products` VALUES (2, 1, 1001, 'Монитор Samsung 943N', 6430);
INSERT INTO `products` VALUES (3, 1, 1001, 'Монитор Samsung 2043NW', 7000);
INSERT INTO `products` VALUES (4, 1, 1001, 'Монитор Samsung SM2232BW', 11500);
INSERT INTO `products` VALUES (6, 1, 1002, 'Монитор Acer AL1916CS', 6000);
INSERT INTO `products` VALUES (7, 1, 1002, 'Монитор Acer AL2216WSD', 8900);
INSERT INTO `products` VALUES (8, 1, 1002, 'Монитор Acer AL2416WBSD', 15000);
INSERT INTO `products` VALUES (9, 2, 1002, 'Ноутбук Acer Aspire 5315', 14500);
INSERT INTO `products` VALUES (10, 2, 1002, 'Ноутбук Acer Extensa 5220', 15500);
INSERT INTO `products` VALUES (11, 2, 1001, 'Ноутбук Samsung R20', 15800);
INSERT INTO `products` VALUES (12, 2, 1001, 'Ноутбук Samsung R60', 20100);
INSERT INTO `products` VALUES (13, 2, 1003, 'Ноутбук Toshiba A210-19A', 24700);
INSERT INTO `products` VALUES (14, 2, 1003, 'Ноутбук Toshiba A210-199', 17000);
INSERT INTO `products` VALUES (15, 1, 1004, 'Монитор BenQ G900W', 5000);
INSERT INTO `products` VALUES (16, 1, 1004, 'Монитор BenQ G700', 4800);
CREATE TABLE `categories` (
`category_id` INT(11) NOT NULL AUTO_INCREMENT,
`title` VARCHAR(255) NOT NULL DEFAULT '',
PRIMARY KEY (`category_id`)
) ENGINE=INNODB DEFAULT CHARSET=cp1251;
INSERT INTO `categories` VALUES (1, 'Мониторы');
INSERT INTO `categories` VALUES (2, 'Ноутбуки');
CREATE TABLE `makers` (
`maker_id` INT(11) NOT NULL AUTO_INCREMENT,
`title` VARCHAR(255) NOT NULL DEFAULT '',
PRIMARY KEY (`maker_id`)
) ENGINE=INNODB DEFAULT CHARSET=cp1251;
INSERT INTO `makers` VALUES (1001, 'Samsung');
INSERT INTO `makers` VALUES (1002, 'Acer');
INSERT INTO `makers` VALUES (1003, 'Toshiba');
INSERT INTO `makers` VALUES (1004, 'BenQ');