Эта статья рассказывает о том, как с помощью технологии 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