В прошлый раз я показывал как можно «на лету» создавать списки html select, данные которых содержались в специальном javascript массиве.
Подготовить такой массива не самая приятная работа, да и место данным, я считаю, в базе данных. Потому логичным продолжением темы с динамически создаваемыми связанными select является пример работы с запросом данных по мере необходимости асинхронно с сервера по средством ajax.
База данных
Начнем с создания структуры данных.
Мне поднадоел пример с картриджами, и сегодня я буду работать с некой военной базой данных видов вооружений.
Для этого я создал две таблички — tree и items.
Таблица tree будет содержать иерархию связанных пунктов для выпадающих списков.
treeID — ключ, pID — указатель на родительский пункт, label — текстовая метка для выпадающего списка, а objID — указатель в таблицу items, для конечных элементов дерева.
В таблице items мы разместим описания видов вооружений.
Описание весьма условное. Кроме ключа в таблице есть title — название вооружения и какие то два параметра, которые мы вообще никак не характеризуем. :)
HTML код
Практически идентичен прошлому примеру.
Мы подключаем библиотеку jQuery и класс — TSEL, создающий связанные списки. TSEL работает с двумя HTML контейнерами, идентификаторы которых мы передадим при инициализации TSEL. Третьим параметром будет url к файлу сервера для обработки ajax запросов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <script type="text/javascript" src="tsel.js"></script> </head> <body> <div id="selector"> <!-- Здесь будут выпадающие списки --> </div> <div id="result"> <!-- Здесь будет описание ед. вооружения --> </div> <script type="text/javascript"> //получаем экземпляр, управляющего списками класса //попутно инициализируем его $(function () { var TS = new TSEL({ selectorID: "selector", resultID: "result", ajaxUrl: "/ajax.php"}); }); </script> </body> </html> |
Javascript создающий списки
Файл tsel.js, подключаемый в секции head содержит класс-функцию объекта, который запрашивает данные на сервере и создаёт в нашем документе связанные выпадающие списки.
Давайте рассмотрим его, не вникая в подробности реализации.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
function TSEL(params) { //счетчик ID контейнеров this.SC = 0; //инициализация this.IDSobj = $('#' + params.selectorID).get(0); this.IDRobj = $('#' + params.resultID).get(0); this.url = params.ajaxUrl; this.buildSelect = function(data) { //эта функция создаёт HTML select tag //и вставляет его в конец контейнера //DIV#selector //на входе - массив элементов списка .. } this.getBrunch = function(parentID) { //тут мы асинхронно получаем массив опций //по ID родительской ветки //при получении данных - вызывается buildSelect //так появляется очередной связанный список .. } this.buildResult = function(data) { //формируем HTML код карточки вооружения //в контейнере DIV#result //выводим все поля объекта data .. } this.getResult = function(id) { //получаем по ajax данные из таблицы items //для описания единицы вооружения //при получении данных вызываем buildResult .. } this.doChild = function (selectObj) { //эта функция вызывается каждый раз при выборе //элемента в списке //здесь решается что делать : //1. загрузить следующий уровень иерархии (getBrunch) //2. или загрузить карточку вооружений (getResult) .. } //при инициализации мы грузим корень дерева this.getBrunch(0); } |
Я не стал полностью приводить код, постарался описать его логику. Файлы примера, а также скрипт базы данных вы найдете в архиве в конце статьи.
Мы имеем дело всего с пятью функциями. Две из них грузят и показывают очередной уровень select-а, ещё две — делают тоже самое для карточки вооружений. А оставшаяся функция реализует логику : какую пару задействовать при выборе пункта списка.
PHP код, реализующий работу сервера
В PHP у нас производится отработка команд клиента, запросы к базе данных. Запросов всего два:
- вернуть список опций ветки дерева, по указанному айди родителя (команда load-brunch),
- вернуть данные об единице вооружения (команда load-object).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<?php //формируем заголовки документа - указываем, что кодировка UTF8 header('Content-Type: text/html; charset=UTF-8'); //если команда не задана - выходим сразу if (empty($_POST['commmand'])) exit; //подключаю хелпер для работы с базой //(там подключение к базе и пара функций) require_once dirname(__FILE__) . '/db.php'; //инициализация выходного массива данных $data = array(); //обработка команд switch ($_POST['commmand']) { case 'load-brunch': //загрузка перечня опций $pid = empty($_POST['parentID'])? 0 : $_POST['parentID']; $res = db_query("SELECT * FROM tree WHERE pID = :pid", array(':pid' => $pid)); if ($res->num_rows) while ($r = $res->fetch_object()) $data[] = $r; break; case 'load-object': //загрузка карточки вооружения $id = empty($_POST['objectID'])? 0 : $_POST['objectID']; $res = db_query("SELECT * FROM items WHERE IDobj = :id", array(':id' => $id)); if ($res->num_rows) $data = $res->fetch_object(); } //вывод в JSON формате echo json_encode($data, true); |
Надеюсь, загрузка данных пояснений не требует. :)
Результат
Как видите, я не использовал никакого оформления. Максимально сократил анализ ошибок и коллизий, связанных с асинхронностью запросов. Пример можно развивать и улучшать как того требует уже ваша задача.
Мне не хотелось создавать лишние таблицы в базе сайта. Потому я ограничусь комментариями к скринам.
Сразу после инициализации появится первый из выпадающих списков. Как видите, он состоит из названий видов вооружений.
Выбирая варианты, вы будете открывать следующий уровень. Я выбрал guns (надо было назвать его cannons или artillery :)) и получил следующий набор вариантов — это уже конечные элементы в моем примере.
Потому при выборе одного из пунктов загрузились данные объекта.
Если с пунктом не связан объект, а также не удалось найти дочерние элементы списка — выскочит alert с надписью — «Ветка пуста!».
Вложенность ничем не ограничена. Кроме того, ветки и листочки могут располагаться на одном уровне.
Архив файлов и скрипт базы данных.
Скачать без регистрации и СМС :)
Архив содержит 5 файлов:
Настройки подключения к вашей базе данных введите в файле db.php. Скрипт для создания таблиц и дамп данных — в test_base.sql. Остальные файлы вы уже знаете.
Классную штуку вы написали, но всётаки я не пойму, а если у меня не 2, а 3 или 5 таблиц в БД, то как мне поступить? Вы говорите что скрипт ваш сам ищет вложенность… но это получается не вложенность, а просто разные таблицы. Та куда вписывать запрос обращения к другим таблицам?
case ‘load-brunch’:
тут выбираем из одной таблицы
case ‘load-object’:
выводит данные на экран
а как выбирать из остальных таблиц, если они есть?
Спасибо заранее за ответ.
Можно не разделять таблицы items и tree, такое разделение предпочтительно в плане нормализации данных. Потому речь идет не о 2х таблицах, а по сути об одной — tree.
Таблица tree нужна для хранения иерархии объектов (в данном случае в виде дерева). В ней мы связываем дочерние и родительские элементы. Каждому элементу дерева сопоставляем pID — parent ID или родительский ID. Т.е. нам не нужно 100500 таблиц для хранения иерархии дерева — нужна всего одна.
Если нужно иметь несколько «объектных» таблиц (items), связанных в одном дереве, то простейшее решение — добавить в tree еще один столбец —
entity_type
, который будет указывать тип сущности дляObjID
.ну всеравно я не пойму как оно подтянет данные из третьей таблицы
вот у меня есть 3 таблицы
brands (id, brand_name)
models (id = brands.id, model_name)
autos(id = brands.id, auto_name)
т.е. у меня все три таблицы имеют связь по id, но всеравно чтоб получить данные из каждой, я даю запрос к каждой, и выпадающий список строю сначала из первой, потом из второй на основании первой, а потом третья на основании второй.
Вот я и не пойму как это реализовать. Или мне надо создать ещё таблицу в которой будут указаны все id и ссылки на дочерние таблицы?
:)
Можно начать с добавления столбца типа объектов в таблицу tree. Второй шаг — адаптировать к работе скрипт, т.к. нужно передавать на сервер дополнительно параметр типа объекта, чтобы программа знала из какой таблицы брать данные. Но надо подумать нужно ли это в вашем случае?
Можно ведь обойтись таблицей autos, объекты которой является конечной целью выбора.
Например, у нас есть два бренда — Audi, BMW, по одной модели в каждом и 2 машины, вот как примерно выглядит дерево (tree):
treeID|pID|label|objID
1|0|Audi|NULL
2|0|BMW|NULL
3|1|A3 Sedan|NULL
4|2|BMW X4|NULL
5|3|A3 Sedan 2015 б/у|1
6|3|A3 Sedan 2017 новая|2
А это таблица autos:
ID|title|descr
1|A3 Sedan 2015 б/у|эта машинка уже с пробегом
2|A3 Sedan 2017 новая|а эта новьё
Вам не надо связывать нижние уровни дерева с какими либо объектами — они служат как бы для навигации.
ладно, попробую сейчас вырастить дерево…
хотя, на мой взгляд, с точки зрения хранения данных… разные таблицы всё же лучше, а так всё свалено в одну…в одно дерево.
Дерево хранит данные не о сущностях, а о об их иерархии. Сущности — отдельно, структура связей между ними — отдельно. Ценность словаря брендов не меняется.
Если у вас есть уже какая то сложная база данных с взаимосвязами объектов, и иерархию можно рассчитать используя эти связи, то таблица tree заполняется (рассчитывается) благодаря этим данным.
собрал дерево…
проблема в следующем, не могу запустить даже ваш пример
вылетает ошибка «Shit happens! error»
Попробуйте запустить проект, разместив его в рамках какого то веб-сервера. Можно взять Denver или OpenServer. А то, мне кажется, вы просто распаковали файлы в случайную папку и жмете на index.html ;)
А еще нужно создать базу данных и настроить к ней подключение…
#Попробуйте запустить проект, разместив его в рамках какого то веб-сервера. Можно взять Denver или OpenServer. А то, мне кажется, вы просто распаковали файлы в случайную папку и жмете на index.html ;)
А еще нужно создать базу данных и настроить к ней подключение…#
ахаха ))) вы думаете я совсем чтоли? )))
Denwer c MySQL всё установлено, базу вашу залил. но не работает. Сейчас появилась возможность попробовать на другом компе, счас отпишусь что получилось.
вот скрин посмотрите, это уже на абсолютно другом компе
http://picua.org/?v=2017-06-03_zk2b0h5xtf452j02yobzb2en7.png
ошибка та же
На вкладке браузера network посмотрите, что с сервера приходит при ajax запросе. Ошибаться там в php, по сути негде, возможно, в php выключена поддержка коротких тегов (допишите вместо < ? - < ?php).
ошибка у вас в коде была, наверное случайно слэш поставили
ajaxUrl: «ajax.php»});
а было так
ajaxUrl: «/ajax.php»});
и оно не находило этот файл
сейчас заработало когда слэш убрал
Ну, отлично, не зря столько писанины :)
Здравствуйте.
А как передать значения выбраных селектов, это возможно?(отправить, записать, вывести текстом в другом месте)