Админка на файлах. Урок 4 и заключительный. Фронтенд

декабрь 9 , 2018
Предыдущая статья Исходники

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

  • Во-первых, само сохранение и отправка данных на сервер.
  • Во-вторых, сохранение данных на сервере. Урок фронтендский, на десяток строк на 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 проектов, где она пригодилась бы. Но тогда сделать это казалось непростой задачей. Как минимум затратной по времени, а время у среднего фрилансера лишним не бывает. Надеюсь, эта админка еще пригодится.

На этом уроке с админкой на файлах мы закончили. Дальше будем развивать тему, но начнем работать с базой интернет-магазина и все как положено. Всем удачи и до встречи.

Что еще почитать по теме

Предыдущая статья Исходники
Заходите в группу в контакте - https://vk.com/webdevkin
Анонсы статей, обсуждения интернет-магазинов, vue, фронтенда, php, гита.
Истории из жизни айти и обсуждение кода.
Как Вам статья? Оцените!