Админка на файлах. Урок 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
- Три урока по сборке фронтенда
- Фильтры и сортировки в интернет-магазине
Истории из жизни айти и обсуждение кода.