Админка на файлах. Урок 4 и заключительный. Фронтенд
В трех предыдущих уроках админки мы подготовили верстку и серверную часть. Осталось вдохнуть жизнь в статичную страничку яваскриптом. Или выдохнуть, кому как нравится. Давайте подумаем, что хотим сделать.
- Во-первых, само сохранение и отправка данных на сервер.
- Во-вторых, сохранение данных на сервере. Урок фронтендский, на десяток строк на php мы все же напишем.
- В-третьих, алерты. Мне нравится, когда система говорит, что какие-то данные изменились и нужно не забыть нажать кнопку Сохранить. Поэтому реализуем и это тоже.
- В-четвертых, все. Раздувать функционал не будем. И так получится неплохая вещь, которую можно использовать в своих проектах.
С постановкой задачи разобрались, давайте приступим.
Добавляем блоки-алерты в верстку
Берем бутстрап и ищем там алерты. Нам нужны два: ворнинг и успех. Оранжевый и зеленый. В первом скажем, что есть несохраненные изменения, а во втором, что данные сохранены. Кидаем 2 дива в низ формы, перед кнопкой Сохранить. Это в файле templates/index.html
Есть несохраненные измененияСохранено
Предусмотрительно задаем дивам айдишники и классы d-none. Айдишники пригодятся в js-коде, а .d-none скроют блоки при загрузке страницы.
Подключаем js-файлы
В конце шаблона подключаем jquery и файлик кастомного кода app.js
Заготовка модуля app.js и основные блоки
Сначала создадим app.js в папке js и добавим в него такую заготовку
var app = (function($) { var $form = $('#settings-form'), $warning = $('#alert-warning'), $success = $('#alert-success'), $button = $('#save-button'); // Инициализация function init() { _bindHandlers(); } // Привязываем события function _bindHandlers() { $form.on('submit', _onSubmitForm); $form.find('[type=checkbox]').on('click', _onClickCheckbox); $form.find('input, select').on('change', _onChangeInput); } // Отправляем форму function _onSubmitForm(e) { // TODO Реализовать } // Меняем галочку в чекбоксе function _onClickCheckbox(e) { $(e.target).next().val(String(e.target.checked)); } // Меняем настройки function _onChangeInput() { // TODO Реализовать } return { init: init } })(jQuery); // Запускаем скрипт jQuery(document).ready(app.init);
Пробежимся по коду.
В начале модуля app инициализируем 4 переменных - форма, два алерта и кнопка Сохранить. Они встретятся дальше в коде.
Моя любимая функция init, с которой начинается работа скрипта. В нашем приложении в init запускается только функция привязки событий _bindHandlers.
В _bindHandlers навешиваются события сабмита формы, клика на чекбокс и изменения инпутов.
Сабмит формы реализуем чуть ниже.
Клик на чекбокс проставляет свое значение в скрытый инпут с таким же name.
Зачем это? Когда отправляем форму на php, то мне, например, неудобно вытаскивать значения чекбоксов из этих непонятных on.
Предпочитаю сразу брать $_POST['checkbox_name'], а не гадать передается ли он на сервер и что в нем лежит. Пусть этим занимается клиент.
Теперь реализуем сабмит формы.
// Отправляем форму function _onSubmitForm(e) { e.preventDefault(); $.ajax({ url: 'api/save.php', data: $form.serialize(), type: 'POST', success: function() { // TODO показать алерт при успешном сохранении } }); }
Элементарный $.ajax. Мы не будем делать никакой валидации, чтобы не усложнять пример. В success напишем три строчки кода работы с алертами. Но после того, как добьем серверную часть.
Сохранение настроек на сервере.
Откроем файл admin.class.php из второго урока. В нем есть функции на чтение настроек, но нет на сохранение. Давайте добавим
// Сохраняем настройки в файл public function save($settings) { file_put_contents($this->valuesFile, json_encode($settings)); $this->setSettings(); }
В первой строке идет запись в values.json, а вторая обновляет свойства класса.
Метод сохранения теперь есть, осталось дернуть его при отправке ajax-запроса на api/save.php. Создадим папку api, а в ней файл save.php. В него напишем это
// Подключаем класс с настройками require_once '../admin.class.php'; // Массив настроек $data = $_POST; // Создаем объект админки $admin = new Admin(); // Сохраняем настройки $admin->save($data);
Упущен один важный момент - валидация данных. Принимать от пользователя массив $_POST без проверки - плохая идея. Но каждый раз писать валидации скучно, поэтому в примерах я их пропускаю. Оставляю Вам реализовать валидацию самим, как захочется. А мы возвращаемся к фронтенду.
Алерты при сохранении и изменении настроек.
Приятная фишечка: изменили одну настройку, увидели сообщение, мол, у вас есть несохраненные изменения. Нажали кнопку Сохранить - предупреждение об изменениях пропало, зато появилось "Успешно сохранено". Блоки-алерты уже есть и в верстке, и даже переменные в js: $warning и $success. Осталось их в нужные моменты скрывать и показывать.
Сначала покажем ворнинг при редактировании настроек. Это в реализации _onChangeInput
// Меняем настройки function _onChangeInput() { $warning.removeClass('d-none'); $success.addClass('d-none'); $button.removeAttr('disabled'); }
Как видим, никакой магии. Показываем ворнинг снятием класса d-none. Скрываем сообщение об успешном сохранении добавлением того же класса. И у кнопки Сохранить убираем disabled, чтобы можно было на нее нажать. Все.
Теперь после сохранения настроек выполним те же процедуры, только наоборот. Допишем 3 строчки в success ajax-запроса. Итоговый _onSubmitForm получится такой
// Отправляем форму function _onSubmitForm(e) { e.preventDefault(); $.ajax({ url: 'api/save.php', data: $form.serialize(), type: 'POST', success: function() { $warning.addClass('d-none'); $success.removeClass('d-none'); $button.attr('disabled', 'disabled'); } }); }
Те же три строки, только с элементами выполняются обратные действия. То есть после успешного сохранения блок ворнинга скрывается, показывается зеленый алерт с надписью "Сохранено" и кнопка Сохранить дизейблится.
Вот теперь все.
Внимательный взгляд заметит, что алерты отрабатывают не идеально четко. Например, если Вы сохраните настройки, потом измените значение 1000 на 5000, появится ворнинг о несохраненных изменениях. Измените обратно на 1000 и ворнинг останется. С Вашей точки зрения настройки не изменились, но наш код это не отслеживает. Если Вам хочется упороться и реализовать это в своей админке, то я только за. Но напомню, что проект изначально рассматривался как быстрый и дешевый способ изменения настроек. Думаю, в текущем виде код эту работу выполняет.
Когда я уже закончил писать, то подумал, жаль, что у меня не было такой мини-админки лет 5 назад во времена фриланса. Сразу вспомнил 5-6 проектов, где она пригодилась бы. Но тогда сделать это казалось непростой задачей. Как минимум затратной по времени, а время у среднего фрилансера лишним не бывает. Надеюсь, эта админка еще пригодится.
На этом уроке с админкой на файлах мы закончили. Дальше будем развивать тему, но начнем работать с базой интернет-магазина и все как положено. Всем удачи и до встречи.
Что еще почитать по теме
- Админка на файлах, урок 1
- Админка на файлах, урок 2, конфиги и бекенд
- Админка на файлах, урок 3, шаблонизатор Twig
- Три урока по сборке фронтенда
- Фильтры и сортировки в интернет-магазине
Истории из жизни айти и обсуждение кода.