Занимаясь backend разработкой, каждый программист сталкивается с тем что любую древовидную структуру - будь то меню или список категорий нужно выводить на сайте не обычным выпадающим списком, а красиво оформленным, что бы пользователю было удобно пользоваться вашей CMS!
Можно красиво форматировать вывод блоков, делать отступы дочерних разделов, но упорядочить разделы будет все равно не удобно. В помощь приходит мощный jQuery плагин Nestable.
Скачать nestable его вы можете на сайте разработчика http://dbushell.github.io/Nestable/
Приступим к созданию древовидного меню сортируемого drag and drop:
База данных будем иметь стандартную структуру. id, name, parent_id а также ячейку order для значений сортировки.
Итак сделаем выборку всех родительских категорий и поместим результат в массив:
$sql = "SELECT * FROM menu WHERE parent_id='0' ORDER BY order"; $result = mysql_query($sql, $connection); $numRows = mysql_num_rows($result);
Теперь выведем на страницу блок с родительскими элементами
echo "\n"; echo "\n\n"; // Блок должен быть здесь не перемещайте его echo "\n";\n\n"; echo "\n"; echo "\n"; while($row = mysql_fetch_array($result)) { echo "\n"; echo "
\n\n"; echo "- "; echo "
\n"; } echo "{$row['id']}: {$row['name']}"; menu_showNested($row['id']); echo "
Наверное вы заметили функцию menu_showNested ? Сейчас мы будем использовать рекурсивную функцию для вывода всех дочерних категорий.
function menu_showNested($parentID) { $sql = "SELECT * FROM menu WHERE parent_id='$parentID' ORDER BY order"; $result = mysql_query($sql, $connection); $numRows = mysql_num_rows($result); if ($numRows > 0) { echo "\n"; echo "\n"; while($row = mysql_fetch_array($result)) { echo "\n"; echo "
\n"; } }- \n"; echo "
\n"; } echo "{$row['id']}: {$row['name']}\n"; menu_showNested($row['id']); echo "
Все меню мы вывели.
Теперь самое сложное - создание и передача массива в формате json обработчику на сервере и сохранение данных в бд
//========================================== nestable script function lagXHRobjekt() { var XHRobjekt = null; try { ajaxRequest = new XMLHttpRequest(); // Firefox, Opera, ... } catch(err1) { try { ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP"); // Noen IE v. } catch(err2) { try { ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP"); // Noen IE v. } catch(err3) { ajaxRequest = false; } } } return ajaxRequest; } //функция отправки методом post массива с порядком в формате json function menu_updatesort(jsonstring) { mittXHRobjekt = lagXHRobjekt(); if (mittXHRobjekt) { mittXHRobjekt.onreadystatechange = function() { if(ajaxRequest.readyState == 4){ var ajaxDisplay = document.getElementById('sortDBfeedback'); ajaxDisplay.innerHTML = ajaxRequest.responseText; } else { // закомментируйте эту строку если не хотите выводить спинер загрузки document.getElementById('sortDBfeedback').innerHTML = ""; } } var tosend = "jsonstring="+jsonstring; ajaxRequest.open("POST","/admin/menu/menu_sortable_save/",true); ajaxRequest.setRequestHeader("Content-type","application/x-www-form-urlencoded"); ajaxRequest.send(tosend); } } $(document).ready(function() { //функция обновления позиций меню var updateOutput = function(e) { var list = e.length ? e : $(e.target), output = list.data('output'); if (window.JSON) { output.val(window.JSON.stringify(list.nestable('serialize')));//, null, 2)); menu_updatesort(window.JSON.stringify(list.nestable('serialize'))); } else { output.val('JSON browser support required for this demo.'); } }; // вызываем функцию для записи изменения порядка меню в бд. $('#nestableMenu').nestable({group: 1}).on('change', updateOutput); // вывод начальной последовательности если элемент существует на странице var variable = $('#nestableMenu').data(); if ( typeof variable !== "undefined" && variable) { updateOutput($('#nestableMenu').data('output', $('#nestableMenu-output'))); } //кнопки развернуть светнуть меню $('#nestable-menu').on('click', function(e) { var target = $(e.target), action = target.data('action'); if (action === 'expand-all') { $('.dd').nestable('expandAll'); } if (action === 'collapse-all') { $('.dd').nestable('collapseAll'); } }); //fix позволяющий кликать на ссылки в nestable $(".dd a").on("mousedown", function(event) { // mousedown prevent nestable click event.preventDefault(); return false; }); $(".dd a").on("click", function(event) { // click event event.preventDefault(); window.location = $(this).attr("href"); return false; }); });
Как видно ничего сложного, я подробней остановлюсь на последних строках! Дело в том что наше меню использует технологию drag and drop следовательно для вызова любой ссылки с блока нашего меню приходится предотвращать выполнение функции drag and drop и выполнять действие перехода по ссылке.
Вот скриншот пример древовидного меню
Теперь самое важное - это серверная часть нашего плагина, где собственно происходит сохранение, обработка и парсинг всех данных.
Следующий код показывает методы класса Menu, контроллера admin и адаптирован для фреймворка codeigniter, по просьбе могу выложить полностью работоспособный вариант этого плагина для codeigniter :
//сохранить порядок меню nestable function menu_sortable_save(){ if ($this->input->post()) { $jsonstring = $this->input->post('jsonstring'); // Декодируем в массив $jsonDecoded = json_decode($jsonstring, true, 64); function parseJsonArray($jsonArray, $parentID = 0) { $return = array(); foreach ($jsonArray as $subArray) { $returnSubSubArray = array(); if (isset($subArray['children'])) { $returnSubSubArray = parseJsonArray($subArray['children'], $subArray['id']); } $return[] = array('id' => $subArray['id'], 'parentID' => $parentID); $return = array_merge($return, $returnSubSubArray); } return $return; } $readbleArray = parseJsonArray($jsonDecoded); // циклом проходимся по массиву и сохраняем в бд foreach ($readbleArray as $key => $value) { if (is_array($value)) { $data = array( 'order' => $key, 'parent_id' => $value['parentID'] ); $this->db->where('id', $value['id']); $this->db->update('menu', $data) or $this->admin_lib->set_admin_alerts('alert_danger', 'Системное сообщение - Ошибка при сортировке записей', 'admin/menu/menu_list_sortable');; } } // вывод сообщения на страницу echo "Порядок категорий успешно сохранен в " . date("y-m-d H:i:s") . "!"; } }
Итак, мы получили отличный плагин для вывода древовидного меню средствами jQuery PHP и MySQL. Результат:
Как и обещал исходники приложения и полные исходники модуля для codeigniter
Mostak Shahid
how to use полные исходники модуля для codeigniter.
Евгений Поляков
MOSTAK SHAHID, исходники модуля - предполагают что вы используете свой движок на codeigniter с расширением hmvc. Просто скопировать папку и установить - не получится. Нужно разобраться в исходном коде и тогда можно использовать его по своему усмотрению. В данный момент уже есть три статьи по созданию движка на codeigniter 3 + HMVC. Этот модуль как раз будем создавать и разбирать код в одной из ближайших статей.