Все ленты — последние статьи

Последовательный выбор с использованием AJAX, jQuery и PHP

В данном уроке мы построим набор элементов для последовательного выбора. Выбор опции будет приводить к обновлению страницы, показывая пользователю дополнительные опции для уточнения выбора. Опции выбора описаны на серверной стороне с помощью PHP, поэтому будет просто переделать пример на использование базы данных.

demosourse

Разметка HTML

Элемент выбора имеет заголовок, который описывает выбираемый параметр. Заголовок и элемент выбора заключены в элемент LI.

Элемент выбора

При добавлении вопросов дополнительные элементы LI создается кодом jQuery. Все они располагаются в неупорядоченном списке #questions. Заголовок и опции данных пунктов обрабатываются как JSON, что будет видно в части PHP. вот какая разметка генерируется для пункта li:
index.html — генерируемый код


01 <ul id="questions">
02 <!-- Генерируется кодом jQuery -->
03 <li>
04 <p>Что желаете купить?</p>
05 <select data-placeholder="Выберите категорию продукта">
06 <option data-connection="phoneSelect" value="Phones">Телефоны</option>
07 <option data-connection="notebookSelect" value="Notebooks">Ноутбуки</option>
08 <option data-connection="tabletSelect" value="Tablets">Планшеты</option>
09 </select>
10 </li>
11 <!-- Следующая секция вставляется в зависимости от выбора -->
12 </ul>

Демонстрационная страница не использует элемент браузера. Потому что мы подключаем плагин jQuery Chosen для преобразования нашего элемента в стильный виджет, который вы видите на экране. Нужно просто вызвать метод chosen() для элемента select, а все остальное сделает плагин.


Код jQuery

Вот что делает наш код jQuery — он получает информацию для элемента выбора в виде JSON с сервера, генерирует разметку HTML и устанавливает обработчики событий для отслеживания изменений. Если элемент выбора меняется, то процесс повторяется с новыми пунктами.

В коде используется две функции JavaScript:

refreshSelects запускает плагин Chosen и привязывает обработчики событий каждый раз, когда новый пункт добавляется на страницу;
fetchSelect запрашивает фид JSON с сервера и генерирует разметку для ответа.

assets/js/script.js
01 $(function(){
02
03 var questions = $('#questions');
04
05 function refreshSelects(){
06 var selects = questions.find('select');
07
08 // Улучшаем элемент selects с помощью плагина Chose
09 selects.chosen();
10
11 // Ждем изменений
12 selects.unbind('change').bind('change',function(){
13
14 // Выбранная опция
15 var selected = $(this).find('option').eq(this.selectedIndex);
16 // Ищем атрибут data-connection
17 var connection = selected.data('connection');
18
19
20 // Удаляем следующий контейнер li (к=если есть)
21 selected.closest('#questions li').nextAll().remove();
22
23 if(connection){
24 fetchSelect(connection);
25 }
26
27 });
28 }
29
30 var working = false;
31
32 function fetchSelect(val){
33
34 if(working){
35 return false;
36 }
37 working = true;
38
39 $.getJSON('ajax.php',{key:val},function(r){
40
41 var connection, options = '';
42
43 $.each(r.items,function(k,v){
44 connection = '';
45 if(v){
46 connection = 'data-connection="'+v+'"';
47 }
48
49 options+= '<option value="'+k+'" '+connection+'>'+k+'</option>';
50 });
51
52 if(r.defaultText){
53
54 // Плагин Chose требует, чтобы был добавлен пустой элемент опции
55 // если нужно выводить текст "Пожалуйста, выберите"
56
57 options = '<option></option>'+options;
58 }
59
60 // Строим разметку для раздела select
61
62 $('<li>
63 <p>'+r.title+'</p>
64 <select data-placeholder="'+r.defaultText+'">
65 '+ options +'
66 </select>
67 <span class="divider"></span>
68 </li>').appendTo(questions);
69
70 refreshSelects();
71
72 working = false;
73 });
74
75 }
76
77 $('#preloader').ajaxStart(function(){
78 $(this).show();
79 }).ajaxStop(function(){
80 $(this).hide();
81 });
82
83 // В начале загружаем выбор продукта
84 fetchSelect('productSelect');
85 });

Отлично! Теперь осталось сделать генерацию фида JSON. Обратите внимание, что функция fetchSelect получает в качестве аргумента строку. Это ключ, который передается в код PHP, обозначающий, какой набор пунктов нам требуется.

Вот как выглядит простой ответ из нашего скрипта PHP:
1 {
2 "items": {
3 "Телефоны": "phoneSelect",
4 "Ноутбуки": "notebookSelect",
5 "Планшеты": ""
6 },
7 "title": "Что желаете купить?",
8 "defaultText": "Выберите категорию продукта"
9 }

Функция fetchSelect проходит циклом все пункты и использует ключи как содержание элементов опций, а значения — как указатели на следующие пункты. Выбор пунктов "Телефоны" и "Ноутбуки" в данном примере будет приводить к генерации новых элементов выбора, а пункта "Планшеты" — нет.

Вид элемента выбора


PHP

Нам нужно где-то хранить информацию о элементах выбора, опциях, которые в них содержатся, и взаимосвязях между ними. В базе данных для решения задачи может использоваться набор строк. Но в нашем примере мы храним данные в статических объектах. Для решения мы определяем простой класс, который будет содержать информацию об элементе выбора.
ajax.php / 1
01 // Будем использовать данный класс для определения каждого элемента select
02
03 class SelectBox{
04 public $items = array();
05 public $defaultText = '';
06 public $title = '';
07
08 public function __construct($title, $default){
09 $this->defaultText = $default;
10 $this->title = $title;
11 }
12
13 public function addItem($name, $connection = NULL){
14 $this->items[$name] = $connection;
15 return $this;
16 }
17
18 public function toJSON(){
19 return json_encode($this);
20 }
21 }

Теперь нам нужно только создать экземпляр данного класса для каждого элемента выбора и вызвать метод addItem() для добавления опций. Данный метод имеет опциональный параметр $connection, который содержит имя зависимого элемента выбора.
ajax.php / 2
01 /* конфигурация элементов select */
02
03 // Продукт
04
05 $productSelect = new SelectBox('Что желаете купить?','Выберите категорию продукта');
06 $productSelect->addItem('Телефоны','phoneSelect')
07 ->addItem('Ноутбуки','notebookSelect')
08 ->addItem('Планшеты','tabletSelect');
09
10 // Типы телефонов
11
12 $phoneSelect = new SelectBox('Какой тип телефона вы хотите?', 'Выберите тип телефона');
13 $phoneSelect->addItem('Смартфон','smartphoneSelect')
14 ->addItem('Обычный телефон','featurephoneSelect');
15
16 // Смартфоны
17
18 $smartphoneSelect = new SelectBox('Какой смартфон вам нужен?','Выберите модель смартфона');
19 $smartphoneSelect->addItem('Samsung Galaxy Nexus')
20 ->addItem('iPhone 4S','iphoneSelect')
21 ->addItem('Samsung Galaxy S2')
22 ->addItem('HTC Sensation');
23
24 // Обычные телефоны
25
26 $featurephoneSelect = new SelectBox('Какой телефон вам нужен?','Выберите модель телефона');
27 $featurephoneSelect->addItem('Nokia N34')
28 ->addItem('Sony Ericsson 334')
29 ->addItem('Motorola');
30
31 // Цвет iPhone
32
33 $iphoneSelect = new SelectBox('Какой цвет аппарата вам нравится?','Выберите цвет');
34 $iphoneSelect->addItem('Белый')->addItem('Черный');
35
36 // Выбор ноутбука
37
38 $notebookSelect = new SelectBox('Какой ноутбук вы хотите купить?', 'Выберите модель ноутбука');
39 $notebookSelect->addItem('Asus Zenbook','caseSelect')
40 ->addItem('Macbook Air','caseSelect')
41 ->addItem('Acer Aspire','caseSelect')
42 ->addItem('Lenovo Thinkpad','caseSelect')
43 ->addItem('Dell Inspiron','caseSelect');
44
45 // Планшет
46
47 $tabletSelect = new SelectBox('Какой планшет является предметом вашей мечты?', 'Выберите модель планшета');
48 $tabletSelect->addItem('Asus Transformer','caseSelect')
49 ->addItem('Samsung Galaxy Tab','caseSelect')
50 ->addItem('iPad 16GB','caseSelect')
51 ->addItem('iPad 32GB','caseSelect')
52 ->addItem('Acer Iconia Tab','caseSelect');
53
54 // Сумка
55
56 $caseSelect = new SelectBox('Возьмёте защитный чехол к вашему аппарату?','');
57 $caseSelect->addItem('Да')->addItem('Нет');
58
59
60 // Регистрируем все пункты выбора в массиве
61
62 $selects = array(
63 'productSelect' => $productSelect,
64 'phoneSelect' => $phoneSelect,
65 'smartphoneSelect' => $smartphoneSelect,
66 'featurephoneSelect' => $featurephoneSelect,
67 'iphoneSelect' => $iphoneSelect,
68 'notebookSelect' => $notebookSelect,
69 'tabletSelect' => $tabletSelect,
70 'caseSelect' => $caseSelect
71 );

Выше приведенный код определяет несколько элементов выбора и размещает их в массиве $selects. Когда скрипт получает запрос AJAX, он просматривает данный массив и возвращает ответ:
ajax.php / 3
01 // Будем просматривать данный массив и возвращать выбранный объект в зависимости
02 // от парметра $_GET['key'] передаваемого jQuery
03
04 // Вы можете модифицировать код для выбора результата из таблицы
05
06 if(array_key_exists($_GET['key'],$selects)){
07 header('Content-type: application/json');
08 echo $selects[$_GET['key']]->toJSON();
09 }
10 else{
11 header("HTTP/1.0 404 Not Found");
12 header('Status: 404 Not Found');
13 }

Вызывая метод toJSON() мы выводим все данные для элементов выбора в формате JSON, который используется клиентской частью jQuery.


Готово!