Freeartists статьи и рецензии о технологияхЭта статья рассказывает о том, как с помощью технологии AJAX сделать связанные списки удобными для пользователя.
Связанные списки это два или более списка. Выбор значения в одном из них влияет на содержание остальных.
Такие списки очень удобны, если вам надо выбрать некий объект с определенными характеристиками.
Вы заходите на сайт автосалона и хотите выбрать машину и вы уже знаете какая модель и какого цвета вам нужна. Естественно, что не все сочетания моделей и цветов есть в наличии. Поэтому, будет гораздо удобнее, выбрав модель машины в одном списке, сразу же посмотреть имеющиеся в наличии цвета данной модели.
Самым простым было бы показывать пользователю два списка. В первом — все модели машин, во втором — все цвета, независимо от их наличия.
Здесь есть две проблемы. Первая проблема заключается в том, что несколько раз выбрав отсутствующие в наличии комбинации модели и цвета, пользователь очень быстро устанет и пойдет на другой сайт. Вторая проблема — паразитивная нагрузка на сервер при выборе несуществующих комбинаций.
Для написания примеров мы будем использовать XHTML, JavaScript и PHP.
Заходя на страницу, пользователь видит только список с названиями моделей. При выборе конкретной модели происходит запрос к серверу, затем создается выборка из базы данных имеющихся цветов выбранной модели и генерация новой страницы со списком цветов.
Вместо базы данных мы будем использовать PHP массивы c набором цветов для каждой модели.
<form action="#" method="get">
<fieldset>
<legend><label for="models">Модели</label></legend>
<select id="models" name="models">
<option value="BentleyAzure">Bentley Azure</option>
<option value="ChevroletCorvette">Chevrolet Corvette</option>
<option value="FerrariEnzo">Ferrari Enzo</option>
</select>
</fieldset>
<?php
// Проверка, пришли ли данные из формы.
if($_GET["models"]){
// Как бы выборка из базы данных.
$colorsArray = array(
"BentleyAzure"=>array("red"=>"Красный","green"=>"Зеленый"),
"ChevroletCorvette"=>array("black"=>"Черный","blue"=>"Синий"),
"FerrariEnzo"=>array("green"=>"Зеленый","black"=>"Черный","yellow"=>"Желтый")
);
$colors = $colorsArray[$_GET["models"]];
?>
<fieldset>
<legend><label for="colors">Цвета</label></legend>
<select id="colors" name="colors">
<?php
// Выводим список доступных цветов.
foreach($colors as $key => $value){
echo '<option value="',$key,'">',$value,'</option>';
}
?>
</select>
</fieldset>
<?php } ?>
<fieldset>
<input type="submit" value="Выбрать" />
</fieldset>
</form>
Естественно, хотелось бы, не заставляя пользователя долго ждать, менять содержимое списка с цветами динамически.
Для этого, сделав выборку из базы данных, на сервере следует создать JavaScript массив с имеющимися в наличии цветами для каждой модели. И написать функцию, меняющую содержание списка цветов в зависимости от выбранной модели.
<head>
<title>Связанные списки, пример № 3</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251" />
<style type="text/css">
fieldset{width:10em;display:block;padding:.5em}
select{width:10em}
#colors{display:none}
</style>
<script type="text/javascript">
// Данные, как бы из базы, сформированные на стороне сервера.
// Обычно находятся в подключаемом JavaScript файле.
var colorsArray = {
BentleyAzure : {red:"Красный",green:"Зеленый"},
ChevroletCorvette : {black:"Черный",blue:"Синий"},
FerrariEnzo : {green:"Зеленый",black:"Черный",yellow:"Желтый"}
}
// Функция, заполняющая список цветами доступными для выбранной модели.
function getColors(_this){
var colors = colorsArray[_this.value];
var _select = document.getElementById("colors");
_select.innerHTML = ""; // Удаляем всех потомков.
for(var i in colors){ // Добавляем доступные цвета.
var option = document.createElement("option");
var optionText = document.createTextNode(colors[i]);
option.appendChild(optionText);
option.setAttribute("value",i);
_select.appendChild(option);
}
// Делаем список цветов видимым.
_select.style.display="inline";
}
</script>
</head>
<body>
<form action="#" method="get">
<fieldset>
<legend><label for="models">Модели</label></legend>
<select id="models" name="models" onchange="getColors(this)">
<option value="BentleyAzure">Bentley Azure</option>
<option value="ChevroletCorvette">Chevrolet Corvette</option>
<option value="FerrariEnzo">Ferrari Enzo</option>
</select>
</fieldset>
<fieldset>
<legend><label for="colors">Цвета</label></legend>
<select id="colors" name="colors"></select>
</fieldset>
<fieldset>
<input type="submit" value="Выбрать" />
</fieldset>
</form>
</body>
С точки зрения usability и минимизации количества данных передаваемых от сервера клиенту, наилучшей будет AJAX реализация.
Для этого мы напишем небольшое JavaScript приложение, которое в ответ на выбор определенной модели, будет динамически менять содержание списка с цветами, загружая данные о цветах с сервера, используя AJAX. Но, сначала, сделаем так, чтобы все цвета присутствовали в списке и напишем проверку с помощью PHP – на случай, если пользователь выберет несуществующую комбинацию. Это нужно для того, чтобы пользователь в любом случае имел возможность выбора, даже если его браузер не поддерживает JavaScript или AJAX.
<body>
<?php
// Проверка, пришли ли данные из формы.
if($_GET["models"]){
// Как бы выборка из базы данных.
$colorsArray = array(
"BentleyAzure"=>array("red"=>"Красный","green"=>"Зеленый"),
"ChevroletCorvette"=>array("black"=>"Черный","blue"=>"Синий"),
"FerrariEnzo"=>array("green"=>"Зеленый","black"=>"Черный","yellow"=>"Желтый")
);
$colors = $colorsArray[$_GET["models"]];
// Проверка на доступность модели этого цвета.
if(array_key_exists($_GET["colors"],$colors)){
echo '<h3 style="color:#090">Модель такого цвета есть в наличии</h3>';
}else{
echo '<h3 style="color:#900">Модель такого цвета отсутствует</h3>';
}
}
?>
<form action="#" method="get">
<fieldset>
<legend><label for="models">Модели</label></legend>
<select id="models" name="models">
<option value="BentleyAzure">Bentley Azure</option>
<option value="ChevroletCorvette">Chevrolet Corvette</option>
<option value="FerrariEnzo">Ferrari Enzo</option>
</select>
</fieldset>
<fieldset>
<legend><label for="colors">Цвета</label></legend>
<select id="colors" name="colors">
<option value="red">Красный</option>
<option value="black">Черный</option>
<option value="green">Зеленый</option>
<option value="blue">Синий</option>
<option value="yellow">Желтый</option>
</select>
</fieldset>
<fieldset>
<input type="submit" value="Выбрать" />
</fieldset>
</form>
</body>
Теперь мы обеспечили доступность нашего интерфейса пользователям тех браузеров, где отключен JavaScript или не поддерживается AJAX.
Напишем небольшой PHP скрипт, отдающий по AJAX запросу доступные цвета машин в формате XML.
<?php
header("Content-Type: text/xml; charset=windows-1251");
$request = $_GET["models"];
if($request){
echo loadData($request);
}
function loadData($request){
// Функция, как бы делающая выборку из базы.
if($request == "BentleyAzure"){
$result = '<color value="red">Красный</color><color value="green">Зеленый</color>';
}elseif($request == "ChevroletCorvette"){
$result = '<color value="black">Черный</color><color value="blue">Синий</color>';
}elseif($request == "FerrariEnzo"){
$result = '<color value="green">Зеленый</color><color value="black">Черный</color>
<color value="yellow">Желтый</color>';
}
if($result){
return $result = '<?xml version="1.0" encoding="windows-1251"?><colors>'.$result.'</colors>';
}
}
?>
И теперь, собственно, AJAX. Наше AJAX приложение будет состоять из двух частей: первая часть будет выполнять AJAX запрос к написанному ранее скрипту ajax.php, а вторая часть обрабатывать полученные данные и записывать их в список цветов.
Для получения данных от сервера мы используем объект XMLHttpRequest. Проблема в том, что его синтаксис и название в разных браузерах неодинаковы. Поэтому мы воспользуемся готовой функцией, предоставляющей кроссбраузерное решение работы с этим объектом.
// Функция, осуществляющая AJAX запрос.
function loadXMLDoc(method,url){
if(window.XMLHttpRequest){
req = new XMLHttpRequest();
req.onreadystatechange = processReqChange;
req.open(method, url, true);
req.send(null);
}else if(window.ActiveXObject){
req = new ActiveXObject("Microsoft.XMLHTTP");
if(req){
req.onreadystatechange = processReqChange;
req.open(method, url, true);
req.send(null);
}
}
}
// Функция, выполняемая при изменении статуса
// запроса, если статус равен 200, данные получены.
function processReqChange(){
if(req.readyState == 4){
if(req.status == 200){
getColors(req.responseXML.documentElement);
}else{
alert("There was a problem retrieving the XML data:\n" + req.statusText);
}
}
}
Не будем вдаваться в подробности реализации AJAX запроса. Укажем лишь, что функция loadXMLDoc осуществляет запрос HTTP методом, переданным ей в качестве параметра по указанному URL. Функция processReqChange выполняется как только придет ответ от сервера. В случае, если данные пришли и HTTP статус равен 200 т. е. «OK», данные передаются в виде XML в функцию getColors.
Осталось только распарсить XML данные с сервера, и вписать их в список доступных цветов.
<head>
<title>Связанные списки, пример № 5</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251" />
<style type="text/css">
fieldset{width:10em;display:block;padding:.5em}
select{width:10em}
</style>
<script type="text/javascript">
// Функция, осуществляющая AJAX запрос.
function loadXMLDoc(method,url){
if(window.XMLHttpRequest){
req = new XMLHttpRequest();
req.onreadystatechange = processReqChange;
req.open(method, url, true);
req.send(null);
}else if(window.ActiveXObject){
req = new ActiveXObject("Microsoft.XMLHTTP");
if(req){
req.onreadystatechange = processReqChange;
req.open(method, url, true);
req.send(null);
}
}
}
// Функция, выполняемая при изменении статуса
// запроса, если статус равен 200, данные получены.
function processReqChange(){
if(req.readyState == 4){
if(req.status == 200){
getColors(req.responseXML.documentElement);
}else{
alert("There was a problem retrieving the XML data:\\n" + req.statusText);
}
}
}
function onChange(_this){
var url = "ajax.php?models="+_this.value;
loadXMLDoc("get",url);
}
function getColors(xml){
var colors = xml.getElementsByTagName("color");
var _select = document.getElementById("colors");
_select.innerHTML = ""; // Удаляем всех потомков.
// Создаем список с доступными цветами.
for(i=0;i<colors.length;i++){
var option = document.createElement("option");
var optionText = document.createTextNode(colors[i].firstChild.data);
option.appendChild(optionText);
option.setAttribute("value",colors[i].getAttribute("value"));
_select.appendChild(option);
}
}
</script>
</head>
<body>
<?php
// Проверка, пришли ли данные из формы.
if($_GET["models"]){
// Как бы выборка из базы данных.
$colorsArray = array(
"BentleyAzure"=>array("red"=>"Красный","green"=>"Зеленый"),
"ChevroletCorvette"=>array("black"=>"Черный","blue"=>"Синий"),
"FerrariEnzo"=>array("green"=>"Зеленый","black"=>"Черный","yellow"=>"Желтый")
);
$colors = $colorsArray[$_GET["models"]];
// Проверка на доступность модели этого цвета.
if(array_key_exists($_GET["colors"],$colors)){
echo '<h3 style="color:#090">Модель такого цвета есть в наличии</h3>';
}else{
echo '<h3 style="color:#900">Модель такого цвета отсутствует</h3>';
}
}
?>
<form action="#" method="get">
<fieldset>
<legend><label for="models">Модели</label></legend>
<select id="models" name="models" onchange="onChange(this)">
<option value="BentleyAzure">Bentley Azure</option>
<option value="ChevroletCorvette">Chevrolet Corvette</option>
<option value="FerrariEnzo">Ferrari Enzo</option>
</select>
</fieldset>
<fieldset>
<legend><label for="colors">Цвета</label></legend>
<select id="colors" name="colors">
<option value="red">Красный</option>
<option value="black">Черный</option>
<option value="green">Зеленый</option>
<option value="blue">Синий</option>
<option value="yellow">Желтый</option>
</select>
</fieldset>
<fieldset>
<input type="submit" value="Выбрать" />
</fieldset>
</form>
</body>
Это AJAX приложение работает в браузерах IE 5+, Opera 9+ и FF 1+.
Здравствуйте!
12 января 2009, 10:47Спасибо за статью!
Можете пояснить каким образом сделать так что бы при выборе элемента из выпадающего списка (это действие реализовано с помощью вашей статьи), не открывался новый элемент , а открывалось поле ввода текста (<input type=””text…)?
JavaScript:
function getColors(){
var conteiner = document.getElementById(“conteiner”);
if(conteiner.getElementsByTagName(“input”)[0]) conteiner.removeChild(conteiner.getElementsByTagName(“input”)[0]);
var input = document.createElement(“input”);
input.setAttribute(“value”,”текст”);
conteiner.appendChild(input);
}
Замените слово “текст”, на данные с сервера.
HTML:
<select id=”colors”… меняем на <div id=”conteiner”></div>
12 января 2009, 12:37Благодарю!
12 января 2009, 13:56Извините, меня за бестактность.
12 января 2009, 19:45Можете еще подсказать как реализовать следующее:
При выборе из списка нужно что бы при выборе разных параметров параметр
</select id="models" name="models"onchange=””Менял свое значение в зависимости от выбранного из списка пункта.
Еще раз извиняюсь за наглость.
Владислав, предлагаю вам разобраться самому, а заодно увеличить свой багаж знаний.
12 января 2009, 20:03Я Вас понимаю можете посоветовать хороший учебник так сказать, просто я порылся – ничего толкового не нашол.
12 января 2009, 20:14AJAX в действии
12 января 2009, 20:21Здравствуйте, жутко извиняюсь все сделал кроме вот этого:
Есть ссылка вида:
Подробнее…
При нажатии на которую запускается скрипт:
function showLogin() {
document.getElementById(‘login’).style.display = ‘block’;
}
Подскажите пожалусто как значение 34 (в onclick=showLogin(34)) передать в php скрипт?
19 января 2009, 20:43Добавите в адрес вызова AJAX’ом PHP скрипта параметр. var url = “ajax.php?models=”+_this.value+”¶m_name=”+34;. Тогда в PHP в массиве $_GET[“param_name”] будет значение вашего параметра.
19 января 2009, 20:58Благодорю!
19 января 2009, 21:00Огромное спасибо!
Здравствуйте!
У меня такой вопрос с помощью AJAX я делаю динамические селекты со странами, регионами и городами, мне нужно выделить столицы красным цветом, для добавления опшинов я использую следующий код:
function addOption (oListbox, text, value, isDefaultSelected, isSelected, highLight)
{
var oOption = document.createElement(“option”);
oOption.appendChild(document.createTextNode(text));
oOption.setAttribute(“value”, value);
if(highLight) oOption.style=”color:red”;
if (isDefaultSelected) oOption.defaultSelected = true;
else if (isSelected) oOption.selected = true;
oListbox.appendChild(oOption);
20 января 2009, 0:54}
к сожалению он корректно работает только в Опере9. IE6 и Mozzila виснут на строчке:
if(highLight) oOption.style=”color:red”;
Можно ли эту ошибку как ни будь обойти, или я неправильно задаю стиль для option?
Попробуйте так: oOption.style.color=”#f00″;
20 января 2009, 9:55Я сделал это!!!!!
29 января 2009, 18:16К большому сожалению полный 0 в JS и AJAX, но общий принцип работы скрипта понял. Теперь МОЯ модификация работает!
Спасибо!
Спасибо за информацию, очень полезно и интересно, потому что подобную задачу сейчас решаю. Могу ли я задать вопрос? если я всё правильно понял, то данные берутся из XML, а можно ли это исключить и взять их из MySQL, если да то как это реализовать ..?
31 марта 2009, 15:01Буду признателен если подскажете, нет – тоже не обижусь.
Можно. Для этого вам на PHP написать прокладку, которая будет делать запросы к БД и отдавать данные в виде XML.
31 марта 2009, 16:12Здравствуйте!
19 апреля 2009, 10:52Я полный ноль по этой теме, но надо сделать такое чудо.
Подскажите, пожалуйста, пример 5 он состоит из одного документа или нет, а то у меня пишет ошибку: “There was a problem retrieving the XML data:\nNot Found”.
Какой код в этом документе надо разместить?
Заранее благодарен
Спасибо огромное за статью, очень выручила.
21 апреля 2009, 10:56Во всем разобрался, и книга классная
Спасибо, наконец-то начал въезжать в аякс. Пытаюсь написать подобное для n-числа связанных селектов. Вот в этом месте
1 июня 2009, 21:28req.onreadystatechange = processReqChange;
не могу понять как в функцию processReqChange мне еще одну переменную передать, что-то вроде req.onreadystatechange = processReqChange(selectname) – это не работает, я может вообще ересь какуюто спрашиваю, в js слабо разбираюсь. Не подскажите заранее благодарен
Думаю, что вопрос давно решенный, но все же напишу ответ:
при перехвате каких либо событий в javascript используется либо псевдоним
функции(как в примере) либо функция генерируется “на лету” как анонимная
пример:
req.onreadystatechange = function(){тело функции};
Естественно всю функцию по понятным причинам вы так писать не будете,
я выхожу из ситуации всегда очень просто и со вкусом так сказать)
req.onreadystatechange = function(){processReqChange(selectname)};
25 июня 2009, 2:24Код из примера 5 не работает в IE v 7.0
20 июля 2009, 11:19Выдает
Строка 41 символ 2
“null” – есть null или не является объектом
Извиняюсь, не обновился кэш IE
20 июля 2009, 11:22Большое спасибо за статью – очень хорошо и пошагово описана работа со связанными списками. Можете добавить в статью, что пример 5 работает и на Google Chrome :)
23 июля 2009, 9:34Нормальный пример, хотя я и редко пользуюсь ajax в основном для написания CMS. Но сказать хочу не об этом
14 сентября 2009, 21:48цитата:
// Функция, как бы делающая выборку из базы.
не лучше ли jav-ой on change получать выбраный элемент и тоже запрашивать данные из базы (т.е. изначально элемент пуст) ведь наличие марки автомобиля тоже может менятся ;)
ЗЫ конечно это несколько усложнит пример
Добрый день.
у меня вопросю. все работает. Нопочему то после выбора сбивается кодировка. т.е. цвета отображаются кракозяблей… хотя в кодах прописан чар сет наш
10 февраля 2010, 15:30Если на стороне сервера и клиента одинаковая кодировка, проблем быть не должно. Обратитесь к вашему серверному приложению на прямую и посмотрите в какой кодировке оно отдает XML.
10 февраля 2010, 15:42utf-8 вместо windows-1251 и проблем с кракозябриками не будет.
14 февраля 2010, 0:59У меня вопрос= пытаюсь запустить этот скрипт на локальном xammp’e – не работает, пробовал также разные скрипты с Ajax’ом с других сайтов – ни одни не пошел. Может быть что у меня что-то на сервере отключено, что HTTPRequest не работает? или в чем проблема?
Все должно работать. Это обычное HTTP взаимодействие. Проверяете вручную адреса, по которым ходит AJAX.
14 февраля 2010, 16:42Спасибо за статью
7 марта 2010, 2:21добрый день,
18 марта 2010, 18:33а как мне вместо перечисления вручную цветов для каждой можелит сделать выборку из базы? Я прописываю это в файле где формат xml, ничего не поулчается, как я поняла, там запросы выполнять нельзя..
День добрый! Такой вопрос – копирую пример №5 на сервер, при попытке выбора марки автомобиля он пишет – There was a problem retrieving the XML data:\\n
что надо сделать чтобы запустить ?
16 апреля 2010, 22:23По адресу ajax.php должен лежать файл, генерирующий XML. Смотри пример выше “Напишем небольшой PHP скрипт, отдающий по AJAX запросу доступные цвета машин в формате XML”.
17 апреля 2010, 11:30Народ скиньте архивчик с пятым примером, вродебы всё норм сделал, а цвета не подгружаются… если можно на депозит пожалуйста…
28 апреля 2010, 0:38Спасибо большое за статью. Всё понятно и просто достаточно написано!
23 августа 2010, 20:12Очень полезно. Спасибо.
3 сентября 2010, 10:52что то в примерах одни ошибки…
1 декабря 2010, 13:59Ошибки исправил. Это следствие переезд на новый хостинг.
1 декабря 2010, 14:25Подскажите пожайлуста. в чём проблема, по примеру 5. списки работают на виртуалке отлично и в мозиле и в IE, переношу на основной сайт, мозила работает, ИЕ ни в какую, как я понял вообще не срабатывает Change, реакции никакой, даже ошибки…
24 декабря 2010, 14:00з.ы. дословно пример работает везде, поэтому следовало бы искать ошибку у себя, но на виртуалке же всё работает, да и на основном в мозиле…уже не знаю что и думать.
24 декабря 2010, 14:06Ну, например, сервер отдает не правильную кодировку для XML или не правильный тип (должно быть text/xml).
Поставьте FireBug в FF и займитесь дебагингом.
24 декабря 2010, 17:31Добрый день как можно сделать несколько таких списков например 4-5?
9 марта 2011, 23:20с запросом данных из одной таблицы SQL в 4-5 столбцов
где можно скачать исходники примеров?
29 августа 2011, 17:59статья устарела
4 января 2012, 6:48Подскажите пожалуйста, как можно при нажатии кнопки отправить сделать так чтобы переходило по определенной ссылке – в зависимости от выбранной модели и цвета?
24 октября 2012, 11:46