Modx ajaxform error

Cниппет для отправки любых форм через ajax. По умолчанию рассчитан на работу с FormIt, но можно использовать и собственный сниппет.

Cниппет для отправки любых форм через ajax. По умолчанию рассчитан на работу с FormIt, но можно использовать и собственный сниппет.

  • Регистрирует нужные скрипты на фронтенде: jQuery.Form и jQuery.jGrowl.
  • Сохраняет в сессию $scriptProperties при вызове сниппета.
  • Выводит указанную форму, прописывая класс ajax_form и скрытый input для получения $scriptProperties.
  • Вешает обработчик на форму, чтобы она отправлялась через ajax.
  • При отправке запускает указанный сниппет для обработки и возвращает ответ от него.
  • Выводит сообщение об успехе, или ошибки, если есть.

Параметры сниппета

Имя По умолчанию Плейсхолдеры
&form tpl.AjaxForm.example Образец чанка с формой, которую нужно обработать.
&snippet FormIt Сниппет для обработки формы.
&frontend_css [[+assetsUrl]]css/default.css Стили оформления формы и полей с ошибками
&frontend_js [[+assetsUrl]]js/default.js Javascript для отправки формы через ajax
&actionUrl [[+assetsUrl]]action.php Адрес коннектора, на который отправляется форма

Всё, что вы указываете AjaxForm, будет передано в вызываемый сниппет.

Обработка своим сниппетом

Вы можете использовать собственный сниппет, вместо FormIt, который будет делать что угодно (хоть создавать страницы на сайте).
Единственное требование — он обязательно должен возвращать JSON массив с ключами:

  • status — 1 или 0, то есть успех или ошибка.
  • message — сообщение о работе сниппета, выводится если status = 0.
  • data — массив для полей с ошибками, в котором ключами является имя поля, а значением — сообщение об ошибке.

Для удобства работы в параметры сниппета передаётся переменная $AjaxForm с классом компонента, чтобы вы могли вызывать из него методы error и success при выдаче ответа.

Простейший пример своего сниппета:

<?php
if (empty($_POST['name'])) {
    return $AjaxForm->error('Ошибки в форме', array(
        'name' => 'Вы не заполнили имя'
    ));
}
else {
    return $AjaxForm->success('Форма прошла проверку');
}

Вызываем так:

[[!AjaxForm?
    &snippet=`MySnippet`
    &form=`tpl.AjaxForm.example`
]]

Этот сниппет ничего не делает, просто возвращает результат проверки имени.

Валидация формы

Сервер может вернуть ошибку отправки формы и массив полей, не прошедших проверку.
Этим полям автоматически будет добавлен CSS класс error, который убирается при последующей отправке.

Так же вы можете запретить отправку формы, используя javascript переменную afValidated — если она объявлена и равна false, то форма не будет отправлена.

Обратите внимание, что все проверки на javascript можно обойти, так что эту переменную стоит использовать только для удобства пользователей, а не для реальной проверки данных.

<script type="text/javascript">
$(document).on('submit', '.ajax_form', function() {
    // Здесь любой код для проверки формы при отправке
    // Я просто печатаю её в консоли бразуреа
    console.log(this);

    // Результатом работы будет выставление глобальной переменной
    afValidated = false; // Или true, если валидация пройдена
});
</script>

[[!AjaxForm]]

Событие af_complete

При получении ответа от сервера вызывается событие af_complete, которое вы можете использовать для обновления содержимого страницы или другой операции javascript.

Вам просто нужно указать функцию, в которую будет передано событие javascript и объект с ответом от сервера. Обратите внимание, что внутри этого объекта есть и отправляющая форма.

$(document).on('af_complete', function(event, response) {
    var form = response.form;
    // Если у формы определённый id
    if (form.attr('id') == 'my_form_3') {
        // Скрываем её!
        form.hide();
    }
    // Иначе печатаем в консоль весь ответ
    else {
        console.log(response)
    }
});

redirect на другую страницу сайта, после успешной отправки формы?

Добавляем id к форме, если его нет и затем в js файл прописать вот такие строки

$(document).on('af_complete', function(event, response) {
    var form = response.form;
    if (form.attr('id') == 'значение id формы') {
       window.location.href = "[[~id страницы]]"
    }
});

Можно просто обернуть в <script>выше приведенный код</script> и подключить в шаблон с формой ближе к закрытию body.

Всплывающие сообщения

По умолчанию AjaxForm выводит сообщения об успешной отправке формы или о наличии ошибок.
Вы можете самостоятельно вызывать их для своих целей:

AjaxForm.Message.success('Зеленый popup');
AjaxForm.Message.error('Красный popup', 1);
AjaxForm.Message.info('Черный popup');

Вторым параметром можно указать «прилипающий» popup — его нужно будет закрыть вручную, бывает полезно для показа серьёзных ошибок.

То есть, просто вызвав сниппет на странице, вы получаете подключенный jQuery.jGrowl и можете показывать приятные всплывающие уведомления на javascript.

Примеры

Отправка email сообщения при помощи FormIt с требованием некоторых полей:

[[!AjaxForm?
    &snippet=`FormIt`
    &form=`tpl.AjaxForm.example`
    &hooks=`email`
    &emailSubject=`Тестовое сообщение`
    &emailTo=`info@domain.com`
    &validate=`name:required,email:required,message:required`
    &validationErrorMessage=`В форме содержатся ошибки!`
    &successMessage=`Сообщение успешно отправлено`
]]

Отладка

При возникновении любых проблем, в первую очередь проверяйте, отправляется ли форма без AjaxForm.
Помните, что AjaxForm — сниппет-обёртка, он не отправляет письма и не проводит проверку формы. Это делает ваш сниппет или FormIt.

Так же не забывайте заглядывать в консоль браузера на предмет ошибок javascript.
Если сервер выдаёт ошибку 500 при отправке, проверьте параметр register_globals у вашего PHP — он должен быть отключен.

Отредактировано: 14 Ноября 2019

AjaxForm это надстройка для компонента FormIt, которая позволяет отправлять результаты форм используя ajax (можно использовать не только FormIt, но и другие скрипты). Для перехода с FormIt на AjaxForm достаточно изменить запись вызова 

[[!AjaxForm?
   &snippet=`FormIt` // указываем сниппет который должен вызывать AjaxForm
   &form=`tpl.form.feedback` // указываем шаблон формы
   ... // остальные строки вызова FormIt
]]

Этапы создания Ajax формы на сайте:

  1. Устанавливаем компоненты FormIt и AjaxForm.
  2. Создаем чанк с HTML формой и модификаторами.
  3. Размещаем вызов в соответствующем ресурсе или шаблоне.

Стандартная форма обратной связи

[[!AjaxForm?
   &snippet=`FormIt`
   &form=`tpl.form.feedback`
   &emailTpl=`mailtpl.feedback`
   &hooks=`email,spam,FormItSaveForm`
   &spamCheckIp=`true`
   &emailFrom=`info@domain.ru`
   &emailSubject=`Письмо с сайта domain.ru`
   &emailTo=`info@domain.ru`
   &validate=`name:required,email:email:required,message:required`
   &validationErrorMessage=`Не заполненны все необходимые поля`
   &successMessage=`Сообщение успешно отправлено`
]]

// содержимое чанка tpl.form.feedback
<form action="" method="post">
     <label for="name">Имя*</label>
     <input id="name" name="name" value="[[!+fi.name]]">

     <label for="email">Email*</label>
     <input id="email" name="email" value="[[!+fi.email]]">

     <label for="message">Сообщение*</label>
     <textarea id="message" name="message" value="[[!+fi.message]]"></textarea>
                      
     <input class="btn gradient-border" type="submit" value="Отправить сообщение">
                     
     [[!+fi.validation_error_message:!empty=`
     <div class="alert">
       <p>Пожалуйста, исправьте следующие ошибки:</p>
           <ul>
               [[!+fi.error.name:!empty=`<li><a href="notes/web/back-end/modx/formit/#name">Поле «Имя» не заполнено</a></li>`]]
               [[!+fi.error.email:!empty=`<li><a href="notes/web/back-end/modx/formit/#email">Поле «Email» не заполнено</a></li>`]]
           </ul>
     </div>`]]
</form>

// чанк mailtpl.feedback
<p>Имя: [[+name]]</p>
<p>Email: [[+email]]</p>
<p>Телефон: [[+phone]]</p>
<p>Сообщение: [[+message]]</p>

В AjaxForm есть дефолтный вид всплывающих окон об успешной отправке и ошибках, чтобы его изменить, надо указать собственные файлы в параметрах frontend_js и frontend_css.

Пример файла без jGrowl, со статичным сообщением во всплывающем окне с id massage

var AjaxForm = {

    initialize: function (afConfig) {
        if (!jQuery().ajaxForm) {
            document.write('<script src="' + afConfig['assetsUrl'] + 'js/lib/jquery.form.min.js"></script>');
        }

        $(document).off('submit', afConfig['formSelector']).on('submit', afConfig['formSelector'], function (e) {
            $(this).ajaxSubmit({
                dataType: 'json',
                data: {pageId: afConfig['pageId']},
                url: afConfig['actionUrl'],
                beforeSerialize: function (form) {
                    form.find(':submit').each(function () {
                        if (!form.find('input[type="hidden"][name="' + $(this).attr('name') + '"]').length) {
                            $(form).append(
                                $('<input type="hidden">').attr({
                                    name: $(this).attr('name'),
                                    value: $(this).attr('value')
                                })
                            );
                        }
                    })
                },
                beforeSubmit: function (fields, form) {
                    //noinspection JSUnresolvedVariable
                    if (typeof(afValidated) != 'undefined' && afValidated == false) {
                        return false;
                    }
                    form.find('.error').html('');
                    form.find('.error').removeClass('error');
                    form.find('input,textarea,select,button').attr('disabled', true);
                    return true;
                },
                success: function (response, status, xhr, form) {
                    form.find('input,textarea,select,button').attr('disabled', false);
                    response.form = form;
                    $(document).trigger('af_complete', response);
                    if (!response.success) {
                        if (response.data) {
                            var key, value, focused;
                            for (key in response.data) {
                                if (response.data.hasOwnProperty(key)) {
                                    if (!focused) {
                                        form.find('[name="' + key + '"]').focus();
                                        focused = true;
                                    }
                                    value = response.data[key];
                                    form.find('.error_' + key).html(value).addClass('error');
                                    form.find('[name="' + key + '"]').addClass('error');
                                }
                            }
                        }
                    }
                    else {
                        form.find('.error').removeClass('error');
                        form[0].reset();
                        //noinspection JSUnresolvedVariable
                        if (typeof(grecaptcha) != 'undefined') {
                            //noinspection JSUnresolvedVariable
                            grecaptcha.reset();
                        }
                        $('.overlay').fadeIn('fast', function () {
                            $('#message').animate({
                                'top': '50%'
                            }, 500);
                        });
                    }
                }
            });
            e.preventDefault();
            return false;
        });

        $(document).on('keypress change', '.error', function () {
            var key = $(this).attr('name');
            $(this).removeClass('error');
            $('.error_' + key).html('').removeClass('error');
        });

        $(document).on('reset', afConfig['formSelector'], function () {
            $(this).find('.error').html('');
            AjaxForm.Message.close();
        });
    }

};

Пример файла с редиректом после успешной отправки

var AjaxForm = {

    initialize: function (afConfig) {
        if (!jQuery().ajaxForm) {
            document.write('<script src="' + afConfig['assetsUrl'] + 'js/lib/jquery.form.min.js"></script>');
        }
        if (!jQuery().jGrowl) {
            document.write('<script src="' + afConfig['assetsUrl'] + 'js/lib/jquery.jgrowl.min.js"></script>');
        }

        $(document).ready(function () {
            $.jGrowl.defaults.closerTemplate = '<div>[ ' + afConfig['closeMessage'] + ' ]</div>';
        });

        $(document).off('submit', afConfig['formSelector']).on('submit', afConfig['formSelector'], function (e) {
            $(this).ajaxSubmit({
                dataType: 'json',
                data: {pageId: afConfig['pageId']},
                url: afConfig['actionUrl'],
                beforeSerialize: function (form) {
                    form.find(':submit').each(function () {
                        if (!form.find('input[type="hidden"][name="' + $(this).attr('name') + '"]').length) {
                            $(form).append(
                                $('<input type="hidden">').attr({
                                    name: $(this).attr('name'),
                                    value: $(this).attr('value')
                                })
                            );
                        }
                    })
                },
                beforeSubmit: function (fields, form) {
                    //noinspection JSUnresolvedVariable
                    if (typeof(afValidated) != 'undefined' && afValidated == false) {
                        return false;
                    }
                    form.find('.error').html('');
                    form.find('.error').removeClass('error');
                    form.find('input,textarea,select,button').attr('disabled', true);
                    return true;
                },
                success: function (response, status, xhr, form) {
                    form.find('input,textarea,select,button').attr('disabled', false);
                    response.form = form;
                    $(document).trigger('af_complete', response);
                    if (!response.success) {
                        AjaxForm.Message.error(response.message);
                        if (response.data) {
                            var key, value, focused;
                            for (key in response.data) {
                                if (response.data.hasOwnProperty(key)) {
                                    if (!focused) {
                                        form.find('[name="' + key + '"]').focus();
                                        focused = true;
                                    }
                                    value = response.data[key];
                                    form.find('.error_' + key).html(value).addClass('error');
                                    form.find('[name="' + key + '"]').addClass('error');
                                }
                            }
                        }
                    }
                    else {
                        AjaxForm.Message.success(response.message);
                        form.find('.error').removeClass('error');
                        form[0].reset();
                        //noinspection JSUnresolvedVariable
                        if (typeof(grecaptcha) != 'undefined') {
                            //noinspection JSUnresolvedVariable
                            grecaptcha.reset();
                        }
						//редиректим на страницу 
						document.location.href = "http://адрес/для/редиректа"
                    }
                }
            });
            e.preventDefault();
            return false;
        });

        $(document).on('keypress change', '.error', function () {
            var key = $(this).attr('name');
            $(this).removeClass('error');
            $('.error_' + key).html('').removeClass('error');
        });

        $(document).on('reset', afConfig['formSelector'], function () {
            $(this).find('.error').html('');
            AjaxForm.Message.close();
        });

    }

};


//noinspection JSUnusedGlobalSymbols
AjaxForm.Message = {
    success: function (message, sticky) {
        if (message) {
            if (!sticky) {
                sticky = false;
            }
            $.jGrowl(message, {theme: 'af-message-success', sticky: sticky});
        }
    },
    error: function (message, sticky) {
        if (message) {
            if (!sticky) {
                sticky = false;
            }
            $.jGrowl(message, {theme: 'af-message-error', sticky: sticky});
        }
    },
    info: function (message, sticky) {
        if (message) {
            if (!sticky) {
                sticky = false;
            }
            $.jGrowl(message, {theme: 'af-message-info', sticky: sticky});
        }
    },
    close: function () {
        $.jGrowl('close');
    },
};

Настройка целей для счетчиков

Отслеживать успешную отправку формы, без изменения кода компонента можно добавив перехватчик в сообщение об успешной отправке:

&successMessage=`Ваше письмо успешно отправлено <script>yaCounterXXXXXXXX.reachGoal('form');</script>`

Документация сниппета AjaxForm

AjaxForm

14 августа 2019, 07:00

Cниппет для отправки любых форм через ajax. По умолчанию рассчитан на работу с FormIt, но можно использовать и собственный сниппет.

  • Регистрирует нужные скрипты на фронтенде: jQuery.Form и jQuery.jGrowl.
  • Сохраняет в сессию $scriptProperties при вызове сниппета.
  • Выводит указанную форму, прописывая класс ajax_form и скрытый input для получения $scriptProperties.
  • Вешает обработчик на форму, чтобы она отправлялась через ajax.
  • При отправке запускает указанный сниппет для обработки и возвращает ответ от него.
  • Выводит сообщение об успехе, или ошибки, если есть.

Параметры сниппета

Имя По умолчанию Плейсхолдеры
&form tpl.AjaxForm.example Образец чанка с формой, которую нужно обработать.
&snippet FormIt Сниппет для обработки формы.
&frontend_css [[+assetsUrl]]css/default.css Стили оформления формы и полей с ошибками
&frontend_js [[+assetsUrl]]js/default.js Javascript для отправки формы через ajax
&actionUrl [[+assetsUrl]]action.php Адрес коннектора, на который отправляется форма

Всё, что вы указываете AjaxForm, будет передано в вызываемый сниппет.

Обработка своим сниппетом

Вы можете использовать собственный сниппет, вместо FormIt, который будет делать что угодно (хоть создавать страницы на сайте).
Единственное требование — он обязательно должен возвращать JSON массив с ключами:

  • status — 1 или 0, то есть успех или ошибка.
  • message — сообщение о работе сниппета, выводится если status = 0.
  • data — массив для полей с ошибками, в котором ключами является имя поля, а значением — сообщение об ошибке.

Для удобства работы в параметры сниппета передаётся переменная $AjaxForm с классом компонента, чтобы вы могли вызывать из него методы error и success при выдаче ответа.

Простейший пример своего сниппета:

<?php
if (empty($_POST['name'])) {
    return $AjaxForm->error('Ошибки в форме', array(
        'name' => 'Вы не заполнили имя'
    ));
}
else {
    return $AjaxForm->success('Форма прошла проверку');
}

Вызываем так:

[[!AjaxForm?
    &snippet=`MySnippet`
    &form=`tpl.AjaxForm.example`
]]

Этот сниппет ничего не делает, просто возвращает результат проверки имени.

Валидация формы

Сервер может вернуть ошибку отправки формы и массив полей, не прошедших проверку.
Этим полям автоматически будет добавлен CSS класс error, который убирается при последующей отправке.

Так же вы можете запретить отправку формы, используя javascript переменную afValidated — если она объявлена и равна false, то форма не будет отправлена.

Обратите внимание, что все проверки на javascript можно обойти, так что эту переменную стоит использовать только для удобства пользователей, а не для реальной проверки данных.

<script type="text/javascript">
$(document).on('submit', '.ajax_form', function() {
    // Здесь любой код для проверки формы при отправке
    // Я просто печатаю её в консоли бразуреа
    console.log(this);

    // Результатом работы будет выставление глобальной переменной
    afValidated = false; // Или true, если валидация пройдена
});
</script>

[[!AjaxForm]]

Событие af_complete

При получении ответа от сервера вызывается событие af_complete, которое вы можете использовать для обновления содержимого страницы или другой операции javascript.

Вам просто нужно указать функцию, в которую будет передано событие javascript и объект с ответом от сервера. Обратите внимание, что внутри этого объекта есть и отправляющая форма.

$(document).on('af_complete', function(event, response) {
    var form = response.form;
    // Если у формы определённый id
    if (form.attr('id') == 'my_form_3') {
        // Скрываем её!
        form.hide();
    }
    // Иначе печатаем в консоль весь ответ
    else {
        console.log(response)
    }
});

redirect на другую страницу сайта, после успешной отправки формы?

Добавляем id к форме, если его нет и затем в js файл прописать вот такие строки

$(document).on('af_complete', function(event, response) {
    var form = response.form;
    if (form.attr('id') == 'значение id формы') {
       window.location.href = "[[~id страницы]]"
    }
});

Можно просто обернуть в <script>выше приведенный код</script> и подключить в шаблон с формой ближе к закрытию body.

Всплывающие сообщения

По умолчанию AjaxForm выводит сообщения об успешной отправке формы или о наличии ошибок.
Вы можете самостоятельно вызывать их для своих целей:

AjaxForm.Message.success('Зеленый popup');
AjaxForm.Message.error('Красный popup', 1);
AjaxForm.Message.info('Черный popup');

Вторым параметром можно указать «прилипающий» popup — его нужно будет закрыть вручную, бывает полезно для показа серьёзных ошибок.

То есть, просто вызвав сниппет на странице, вы получаете подключенный jQuery.jGrowl и можете показывать приятные всплывающие уведомления на javascript.

Примеры

Отправка email сообщения при помощи FormIt с требованием некоторых полей:

[[!AjaxForm?
    &snippet=`FormIt`
    &form=`tpl.AjaxForm.example`
    &hooks=`email`
    &emailSubject=`Тестовое сообщение`
    &emailTo=`info@domain.com`
    &validate=`name:required,email:required,message:required`
    &validationErrorMessage=`В форме содержатся ошибки!`
    &successMessage=`Сообщение успешно отправлено`
]]

Отладка

При возникновении любых проблем, в первую очередь проверяйте, отправляется ли форма без AjaxForm.
Помните, что AjaxForm — сниппет-обёртка, он не отправляет письма и не проводит проверку формы. Это делает ваш сниппет или FormIt.

Так же не забывайте заглядывать в консоль браузера на предмет ошибок javascript.
Если сервер выдаёт ошибку 500 при отправке, проверьте параметр register_globals у вашего PHP — он должен быть отключен.

На чтение 26 мин Просмотров 23.5к. Опубликовано 03.09.2020
Обновлено 29.01.2023

Содержание

  1. AjaxForm vs FormIt — что лучше использовать. Плюсы и минусы.
  2. Документация по AjaxForm
  3. Основные параметры
  4. Всплывающие сообщения
  5. Обработка своим сниппетом
  6. Валидация формы
  7. Событие af_complete
  8. Пример с оф. документации
  9. Решение проблем с отправкой писем (Отладка)
  10. Реальные примеры создания форм обратной связи
  11. Задача 1. Переписать вызовы контактной формы с Formit на AjaxForm.
  12. Задача 2. Создать форму заказа обратного звонка в модальном окне.
  13. AjaxForm на fenom
  14. Финальный штрихи
  15. Задача 3. Продвинутая форма с вложениями при помощи Formit + AjaxForm
  16. Плюшки
  17. Закрываем модальное окно после отправки формы
  18. Изменение стилей и положения всплывающего окна Ajaxform.
  19. Оптимизация скорости загрузки сайта. 
  20. redirect на другую страницу сайта, после успешной отправки формы?
  21. Настройка отправки целей в AjaxForm
  22. Как передать адрес и заголовок страницы
  23. Чекбокс — согласие с политикой обработки персональных данных
  24. Дополнительно

В прошлом уроке мы разобрали документация по пакету FormIt и построили контактную форму. Сегодня логическое продолжение.

В данной уроке мы рассмотрим бесплатный компонент AjaxForm — сниппет для отправки форм через ajax (отправка форм без перезагрузки, который по умолчанию рассчитан на работу с пакетом FormIt, но можно написать собственный обработчик.

Установить AjaxForm можно через репозиторий modstore.

AjaxForm vs FormIt — что лучше использовать. Плюсы и минусы.

Мне не нравится, что аякс форм, при инициализации регистрирует на фронтенде скрипты: jQuery.Form и jQuery.jGrowl. Плюс ко всему этому требует наличия подключения jQuery.

По этому, когда на странице 1 форма, я обычно использую чистый FormIt, т.к. он не добавляет своих библиотек. Когда на странице по 3-10 форм (это сейчас модно), я всегда использую AjaxForm, т.к. нет проблем с отправкой (дублированием писем) с разных форм + есть дополнительные плюшки.

  • Сохраняет в сессию $scriptProperties при инициализации сниппета.
  • Выводит указанную форму, прописывая класс ajax_form и скрытый input для получения $scriptProperties.
  • Вешает обработчик для отправки форм через ajax — без перезагрузки страницы.
  • При отправке запускает указанный вами сниппет (обработчик) и возвращает ответ от него.
  • Выводит сообщение об успехе отправки, или ошибки.

Документация по AjaxForm

Основные параметры

Имя По умолчанию Плейсхолдеры и примечания
&form tpl.AjaxForm.example Образец чанка с формой, который можно взять за основу.
&snippet FormIt Можете написать свой сниппет для обработки формы.
&frontend_css [[+assetsUrl]]css/default.css Стандартные стили оформления формы и полей с ошибками, чтобы отключить их вывод, укажите пустое значение.
&frontend_js [[+assetsUrl]]js/default.js Javascript для отправки формы через ajax
&actionUrl [[+assetsUrl]]action.php Адрес коннектора, на который отправляется форма

Всплывающие сообщения

По умолчанию AjaxForm выводит сообщения об успешной отправке формы или о наличии ошибок. Можете самостоятельно вызывать их для своих целей:

AjaxForm.Message.success('Зеленый popup');
AjaxForm.Message.error('Красный popup', 1);
AjaxForm.Message.info('Черный popup');

Указав второй параметр (, 1) — вы получаете «прилипающий» popup, который не закрывается автоматически (а только по нажатию на крестик) — бывает полезно для показа серьёзных ошибок.

примеры всплывающих сообщений с AjaxForm

За выплывающие уведомления, отвечает подключаемая по умолчанию  javascript библиотека jQuery.jGrowl.

Обработка своим сниппетом

Хотите вместо FormIt, использовать собственный сниппет, который будет делать что угодно (например создавать страницы на сайте)? Без проблем, единственное требование — он обязательно должен возвращать JSON массив с ключами:

  • status — 1 или 0, то есть успех или ошибка.
  • message — сообщение о работе сниппета, выводится если status = 0.
  • data — массив для полей с ошибками, в котором ключами является имя поля, а значением — сообщение об ошибке.

Для удобства работы в параметры сниппета передаётся переменная $AjaxForm с классом компонента, чтобы вы могли вызывать из него методы error и success при выдаче ответа.

Простейший пример своего сниппета:

<?php
if (empty($_POST['name'])) {
    return $AjaxForm->error('Ошибки в форме', array(
        'name' => 'Вы не заполнили имя'
    ));
}
else {
    return $AjaxForm->success('Форма прошла проверку');
}

Примечание: данный сниппет ничего не делает, просто возвращает результат проверки имени.

Вызываем так:

[[!AjaxForm?
    &snippet=`MySnippet`
    &form=`tpl.AjaxForm.example`
]]

Валидация формы

Сервер может вернуть ошибку отправки формы и массив полей, не прошедших проверку. Этим полям автоматически будет добавлен CSS класс error, который убирается при последующей отправке.

Так же вы можете запретить отправку формы, используя javascript переменную afValidated — если она объявлена и равна false, то форма не будет отправлена.

Важно! Все проверки на javascript можно обойти, так что лучше не использовать эту переменную стоит использовать для реальной проверки данных. Используйте только для удобства пользователей.

<script>
$(document).on('submit', '.ajax_form', function() {
    // Здесь любой код для проверки формы при отправке
    console.log(this);

    // Результатом работы будет выставление глобальной переменной
    afValidated = false; // Или true, если валидация пройдена
});
</script>

Событие af_complete

При получении ответа от сервера вызывается событие af_complete, которое вы можете использовать для обновления содержимого страницы или другой операции javascript.

Вам просто нужно указать функцию, в которую будет передано событие javascript и объект с ответом от сервера. Обратите внимание, что внутри этого объекта есть и отправляющая форма.

$(document).on('af_complete', function(event, response) {
    var form = response.form;
    // Если у формы определённый id
    if (form.attr('id') == 'my_form_3') {
        // Скрываем её!
        form.hide();
    }
    // Иначе печатаем в консоль весь ответ
    else {
        console.log(response)
    }
});

Пример с оф. документации

Отправка email сообщения при помощи FormIt с требованием некоторых полей:

[[!AjaxForm?
    &snippet=`FormIt`
    &form=`tpl.AjaxForm.example`
    &hooks=`email`
    &emailSubject=`Тестовое сообщение`
    &emailTo=`info@domain.com`
    &validate=`name:required,email:required,message:required`
    &validationErrorMessage=`В форме содержатся ошибки!`
    &successMessage=`Сообщение успешно отправлено`
]]

Решение проблем с отправкой писем (Отладка)

При возникновении любых проблем, в первую очередь проверяйте, отправляется ли форма без AjaxForm. Помните, что AjaxForm — сниппет-обёртка, он не отправляет письма и не проводит проверку формы. Это делает ваш сниппет или FormIt.

Так же не забывайте заглядывать в консоль браузера на предмет ошибок javascript. Если сервер выдаёт ошибку 500 при отправке, проверьте параметр register_globals у вашего PHP — он должен быть отключен.

Официальная документация по компоненту AjaxForm.

Реальные примеры создания форм обратной связи

Стоит 3 задачи, рассмотрим их.

Задача 1. Переписать вызовы контактной формы с Formit на AjaxForm.

Перепишем форму с прошлого урока. По большому счету ничего особо не меняется. Помещаем код формы в отдельный чанк, пусть будет contact_form (код на modparser берите с прошлого урока, здесь приведу на fenom):

<form class="ajax_form af_example contact-form custom-form-style-1" action="{$_modx->makeUrl($_modx->resource.id, '', '', 'full')}" method="post">
        {$fi.successMessage}
        {$fi.validation_error_message}
        <div class="row row-gutter-sm">
            <div class="form-group col mb-3">
                <input type="text" value="" class="form-control" name="name" id="name" required placeholder="Ваше имя">
                <span class="error_name">{$fi.error.name}</span>
            </div>
        </div>
        <div class="row row-gutter-sm">
            <div class="form-group col mb-3">
                <input type="email" value="" class="form-control" name="email" placeholder="Введите ваш E-mail">
                <span class="error_email">{$fi.error.email}</span>
            </div>
        </div>
        <div class="row">
            <div class="form-group col mb-3">
                <textarea rows="4" class="form-control" name="message" placeholder="Сообщение"></textarea>
                <span class="error_message">{$fi.error.message}</span>
            </div>
        </div>
        <div class="row appear-animation" data-appear-animation="fadeInUpShorterPlus" data-appear-animation-delay="1500">
            <div class="form-group col mb-0">
                <button type="submit" class="btn btn-primary btn-modern font-weight-bold custom-btn-border-radius custom-btn-arrow-effect-1 text-3 px-5 py-3">
                	ОТПРАВИТЬ
                	<svg class="ms-2" version="1.1" viewBox="0 0 15.698 8.706" width="17" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    					<polygon stroke="#FFF" stroke-width="0.1" fill="#FFF" points="11.354,0 10.646,0.706 13.786,3.853 0,3.853 0,4.853 13.786,4.853 10.646,8 11.354,8.706 15.698,4.353 "/>
    				</svg>
                </button>
            </div>
        </div>
    </form>

Здесь у нас особо ничего не поменялось, единственное к элементу form я добавил дополнительные классы ajax_form af_example.

И подсветка ошибок у нас была <span class="error">{$fi.error.namePolya}</span>, стала <span class="error_namePolya">{$fi.error.namePolya}</span>.

А вызов FormIt, переписан так:

{'!AjaxForm' | snippet : [
    'snippet' => 'FormIt',
    'hooks' => 'email',
    'validate' => 'name:required:maxLength=^21^,email:email:required,message:required:minLength=^30^',
    'form' => 'contact_form',
    'emailTpl' => 'tplForm',
    'emailTo' => $_modx->config.emailsender,
    'emailFrom' => 'noretly@site.ru',
    'emailSubject' => 'Сообщение со страницы контакты на сайте ' ~ $_modx->config.site_name,
    'successMessage' => '<div class="contact-form-success alert alert-success mt-4"><strong>Успешно!</strong> Ваше сообщение отправлено нам.</div>',
    'validationErrorMessage' => '<div class="contact-form-success alert alert-danger mt-4"><strong>Ошибка!</strong> Произошла ошибка при отправке вашего сообщения.</div>'
]}

Здесь у нас тоже ничего не поменялось, теперь просто запускается AjaxForm, следом инициализируется FormIt.

Теперь у нас выводятся ошибки без каких-либо перезагрузок страниц.

Вывод ошибок

fi.successMessage и fi.validation_error_message выводятся во всплывающем окне.

Задача 2. Создать форму заказа обратного звонка в модальном окне.

Форма должна выполнять следующее:

  • сохранять данные в админке MODX;
  • поле ввода телефона должно быть по маске;
  • после успешной отправки должно выводиться сообщение: «Спасибо за обращение в нашу компанию! Менеджер свяжется с вами в ближайшее время»;
  • модальное окно после отправки формы должно закрываться.

Решение.

Т.к. верстка построена на bootstrap:

Подключение bootstrap

версии 5.2.3:

5.2.3

Можно использовать его официальную документацию (брать код различных элементов от туда), разделы modal (https://getbootstrap.com/docs/5.2/components/modal/) и forms (https://getbootstrap.com/docs/5.2/forms/overview/).

Но т.к. разработчики Porto внесли свои небольшие изменения во внешний вид, возьмем их разметку модальных окон и форм у них. Находится в файле elements-modals.html, там есть Launch Form Modal, со следующим кодом:

Launch Form Modal

Сразу перепишем ее под наши нужды, разметка кнопки у нас получается такой:

<button class="btn btn-modern btn-primary" data-bs-toggle="modal" data-bs-target="#formModal">
    Заказать звонок						
</button>

Кстати эту кнопку можно поместить в чанк с самой формой, если хотите.

Ее можно поместить в любом месте сайта вместе с вызовом аякс форм. Получается разметку модального окна и формы выносим в отдельный чанк, пусть будет modal_form:

<div class="modal fade" id="formModal" tabindex="-1" role="dialog" aria-labelledby="formModalLabel" aria-hidden="true">
	<div class="modal-dialog">
		<div class="modal-content">
			<div class="modal-header">
				<h4 class="modal-title" id="formModalLabel">Заказ звонка</h4>
				<button type="button" class="btn-close" data-bs-dismiss="modal" aria-hidden="true">×</button>
			</div>
			<form id="demo-form" class="ajax_form af_example mb-4" action="[[~[[*id]]? &scheme=`full`]]" method="post">
				<div class="modal-body">
					<div class="form-group row align-items-center">
						<label class="col-sm-3 text-start text-sm-end mb-0">Имя</label>
						<div class="col-sm-9">
							<input type="text" name="name" class="form-control" placeholder="Введите свое имя" required/>
							<span class="error_name">[[+fi.error.name]]</span>
						</div>
					</div>
					<div class="form-group row align-items-center">
						<label class="col-sm-3 text-start text-sm-end mb-0">Телефон</label>
						<div class="col-sm-9">
							<input type="text" id="phone" name="phone" class="form-control" placeholder="Укажите телефон" required/>
							<span class="error_phone">[[+fi.error.phone]]</span>
						</div>
					</div>
					[[+fi.successMessage]]
					[[+fi.validation_error_message]]
				</div>
				<div class="modal-footer">
					<button type="button" class="btn btn-light" data-bs-dismiss="modal">Закрыть</button>
					<button type="submit" class="btn btn-primary">Позвоните мне</button>
				</div>
			</form>
		</div>
	</div>
</div>

Маску ввода сделаем при помощи jQuery библиотеки maskedinput, на этом останавливаться не буду смотрите урок: Маска ввода для полей HTML форм на jQuery. А еще лучше возьмите крохотный js для маски из урока: Маска ввода телефона в input на чистом JS.

Напомню, что все input, textarea должны иметь атрибут name — это обязательно!

Делаем вызов формы. Чтобы форма начала сохранятся в админке нам нужно добавить хук FormItSaveForm, указать название формы (formName), перечислить поля, которые нужно сохранить (formFields) и названия полей (fieldNames), в итоге получаем следующий вызов.

[[!AjaxForm?
    &snippet=`FormIt`
    &hooks=`email,FormItSaveForm`
    &validate=`name:required:maxLength=^21^,phone:required:maxLength=^17^`
    &form=`modal_form`
    &emailTpl=`tplForm`
    &fromName=`Заказ звонка`
	&formFields=`name,phone`
	&fieldNames=`name==Имя,phone==Телефон`
    &emailSubject=`Заказ звонка с сайта [[++site_name]]`
    &emailTo=`[[++emailsender]]`
    &emailFrom=`noretly@[[++base_url]]`
    &successMessage=`<p class="h4 text-white">Спасибо за обращение в нашу компанию! <br>Менеджер свяжется с вами в ближайшее время</p>`
]]

AjaxForm на fenom

Чанк с формой на fenom.

<div class="modal fade" id="formModal" tabindex="-1" role="dialog" aria-labelledby="formModalLabel" aria-hidden="true">
	<div class="modal-dialog">
		<div class="modal-content">
			<div class="modal-header">
				<h4 class="modal-title" id="formModalLabel">Заказ звонка</h4>
				<button type="button" class="btn-close" data-bs-dismiss="modal" aria-hidden="true">×</button>
			</div>
			<form id="demo-form" class="ajax_form af_example mb-4" action="{$_modx->makeUrl($_modx->resource.id, '', '', 'full')}" method="post">
			    <div class="modal-body">
					<div class="form-group row align-items-center">
						<label class="col-sm-3 text-start text-sm-end mb-0">Имя</label>
						<div class="col-sm-9">
							<input type="text" name="name" class="form-control" placeholder="Введите свое имя" required/>
							<span class="error_name">{$fi.error.name}</span>
						</div>
					</div>
					<div class="form-group row align-items-center">
						<label class="col-sm-3 text-start text-sm-end mb-0">Телефон</label>
						<div class="col-sm-9">
							<input type="text" name="phone" class="tel form-control" placeholder="Укажите телефон" required/>
							<span class="error_phone">{$fi.error.phone}</span>
						</div>
					</div>
    				{$fi.successMessage}
    				{$fi.validation_error_message}
    			</div>
    			<div class="modal-footer">
    				<button type="button" class="btn btn-light" data-bs-dismiss="modal">Закрыть</button>
    				<button type="submit" class="btn btn-primary">Позвоните мне</button>
    			</div>
			</form>
		</div>
	</div>
</div>

Вызов формы на fenom.

{'!AjaxForm' | snippet : [
    'snippet' => 'FormIt',
    'hooks' => 'email,FormItSaveForm',
    'validate' => 'name:required:maxLength=^21^,phone:required:maxLength=^17^',
    'form' => 'modal_form',
    'emailTpl' => 'tplForm',
    'fromName' => 'Заказ звонка',
	'formFields' => 'name,phone',
	'fieldNames' => 'name==Имя,phone==Телефон',
    'emailSubject' => 'Заказ звонка с сайта ' ~ $_modx->config.site_name,
    'emailTo' => $_modx->config.emailsender,
    'emailFrom' => 'noretly@site.ru',
    'successMessage' => '<p class="h4 text-white">Спасибо за обращение в нашу компанию! <br>Менеджер свяжется с вами в ближайшее время</p>',
]}

Финальный штрихи

Помните я в прошлом уроке рассказывал про универсальный обработчик форм, что нет смысла создавать под каждую форму отдельный обработчик, пришла пора его модифицировать. Открываем чанк  и вносим в него поля с модикоторами проверки на пустоту, в конечном итоге он приобретает вид:

<p><strong>Имя</strong>: {$name}</p> 
{if $phone?}<p><strong>Телефон</strong>: {$phone}</p>{/if}
{if $email?}<p><strong>Почта</strong>: <a href="mailto:{$email}">{$email}</a></p>{/if} 
{if $message?}<p><strong>Сообщение</strong>: {$message}</p>{/if}
тоже самое на fenom:
<p><strong>Имя</strong>: [[+name]]</p>`]]
[[+phone:!empty=`<p><strong>Телефон</strong>: [[+phone]]</p>`]]
[[+email:!empty=`<p><strong>Почта</strong>: [[+email]]</p>`]]
[[+message:!empty=`<p><strong>Сообщение</strong>: [[+message]]</p>`]]

Не проверяю на пустоту только имя, т.к. оно используется во всех формах и везде оно обязательное для заполнения.

Ну и осталось добавить пару строк js, чтобы окно закрывалось, об этом информация ниже.

Тестируем, пробуем заполнить и отправить:

Тест формы

И данные падают в админку Пакеты — Formit

Данные формы в админке

Задача 3. Продвинутая форма с вложениями при помощи Formit + AjaxForm

Будем создавать вот такую форму.

Продвинутая форма с вложениями при помощи Formit + AjaxForm

По сути она достаточно простая. но ее особая особенность. это вложения.

И так. данная форма имеет, вот такой html код:

<form class="ajax_form" method="post" action="" enctype="multipart/form-data">
 <fieldset>
  <div class="row"> 
   <div class="col-sm-4">  
    <div class="fancy-form">
	<i class="fa fa-user"></i>
	<input type="text" name="name" required="" class="form-control" placeholder="Ваше имя*" value="">
    </div>
   </div>
   <div class="col-sm-4"> 
    <div class="fancy-form">
	<i class="fa fa-at"></i>
	<input type="text" name="email" required="" class="form-control" placeholder="Ваш email*" value="">
    </div>
   </div>
   <div class="col-sm-4"> 
    <div class="fancy-form">
	<i class="fa fa-phone"></i>
	<input type="text" class="form-control" id="pfone" name="pfone" required="" placeholder="Ваш телефон*" value="">
    </div>
   </div>
  </div>
  <div class="fancy-form bottom-21">
	<select class="form-control pointer" name="department">
		<option value="">--- Выберите тип работы ---</option>
		<option value="Разработка-сайта-под-ключ">Разработка сайта под ключ</option>
		<option value="Доработка-сайта">Доработка сайта</option>
		<option value="Адаптация-имеющегося-сайта">Адаптация имеющегося сайта</option>
		<option value="Разработка-верстка-дизайна-сайта">Разработка/верстка дизайна сайта</option>
		<option value="Продвижение-сайта">Продвижение сайта</option>
		<option value="Рекламные-компании">Рекламные компании</option>
		<option value="Разработка-дизайна-групп">Разработка дизайна групп</option>
		<option value="Продвижение-групп">Продвижение групп</option>
		<option value="Прочее">Прочее</option>
	</select>
  </div>
  <div class="fancy-form bottom-21">
	<textarea rows="5" name="message" required="" class="form-control word-count" data-maxlength="2000" data-info="textarea-words-info" placeholder="Примечания / пожелания"></textarea>
	<i class="fa fa-comments"><!-- icon --></i>
 	<span class="error error_name"></span>
  </div>
  <div class="input-group file-upload w100">
  <div class="input-group"><span class="input-group-addon"><i class="fa fa-paperclip"></i></span><input class="custom-file-upload custom-file-upload-hidden" placeholder="Ваше задание, методичка и т.д.*" type="file" id="file" name="attachment" data-btn-text="Выберите файл" tabindex="-1" style="position: absolute; left: -9999px;"><input type="text" class="form-control file-upload-input text-left"><span class="input-group-btn" tabindex="-1"><button type="button" class="file-upload-button btn btn-primary">Выберите файл</button></span></div>
  </div>
</fieldset>
<button type="submit" class="btn btn-3d btn-xmg btn-primary btn-w100">Отправить</button>
</form>

По сути обычная немного модифицированная bootstrap разметка.

Обязательный атрибут для использования вложений в MODX: enctype=»multipart/form-data»

Ну а теперь ближе к делу:

Создаем чанк, ну к к примеру form-uslugi и помещаем в него весть вышеприведенный код, далее модифицируем его под Formit + AjaxForm, получаем:

<form method="post" action="[[~[[*id]]]]" enctype="multipart/form-data">
    <fieldset>
        <div class="row"> 
            <div class="col-sm-4">  
                <div class="fancy-form">
                	<i class="fa fa-user"></i>
                	<input type="text" name="name" required="" class="form-control" placeholder="Ваше имя*" value="[[+fi.name]]">
                	<span class="error error_name">[[+fi.error.name]]</span>
                </div>
            </div>
            <div class="col-sm-4"> 
                <div class="fancy-form">
                	<i class="fa fa-at"></i>
                	<input type="text" name="email" required="" class="form-control" placeholder="Ваш email*" value="[[+fi.email]]">
                	<span class="error error_name">[[+fi.error.email]]</span>
                </div>
            </div>
            <div class="col-sm-4"> 
                <div class="fancy-form">
                	<i class="fa fa-phone"></i>
                	<input type="text" class="form-control" id="pfone" name="pfone" required="" placeholder="Ваш телефон*" value="[[+fi.pfone]]">
                	<span class="error error_name">[[+fi.error.pfone]]</span>
                </div>
            </div>
        </div>
        <div class="fancy-form bottom-21">
        	<select class="form-control pointer" name="department">
        		<option value="">--- Выберите тип работы ---</option>
        		<option value="Разработка-сайта-под-ключ">Разработка сайта под ключ</option>
        		<option value="Доработка-сайта">Доработка сайта</option>
        		<option value="Адаптация-имеющегося-сайта">Адаптация имеющегося сайта</option>
        		<option value="Разработка-верстка-дизайна-сайта">Разработка/верстка дизайна сайта</option>
        		<option value="Продвижение-сайта">Продвижение сайта</option>
        		<option value="Рекламные-компании">Рекламные компании</option>
        		<option value="Разработка-дизайна-групп">Разработка дизайна групп</option>
        		<option value="Продвижение-групп">Продвижение групп</option>
        		<option value="Прочеее">Прочеее</option>
        	</select>
        </div>
        <div class="fancy-form bottom-21">
        	<textarea rows="5" name="message" required="" class="form-control word-count" data-maxlength="2000" data-info="textarea-words-info" placeholder="Примечания / пожелания"></textarea>
        	<i class="fa fa-comments"><!-- icon --></i>
        	<span class="error error_name">[[+fi.error.message]]</span>
        </div>
        <div class="input-group file-upload w100">
        <input class="custom-file-upload custom-file-upload-hidden" type="file" id="file" name="attachment" data-btn-text="Выберите файл" tabindex="-1" style="position: absolute; left: -9999px;">
        </div>
    </fieldset>
<button type="submit" class="btn btn-3d btn-xmg btn-primary btn-w100">Отправить</button>
[[+fi.success:is=`1`:then=`
<div class="alert alert-success">[[+fi.successMessage]]</div>`]]
[[+fi.validation_error:is=`1`:then=`<div class="alert alert-error">[[+fi.validation_error_message]]</div>`]]
</form>

Далее создаем 2й чанк tpl-form-uslugi, со следующим содержимым

<p>Имя: [[+name]]</p>
<p>Email: [[+email]]</p>
<p>Телефон: [[+pfone]]</p>
<p>Тип работы: [[+department]]</p>
<p>Сообщение: [[+message]]</p>
<p>Файл: [[+attachment]]</p>

Можно вообще сделать для всех форм универсальный обработчик, при помощи модификаторов, вот пример универсального обработчика на fenom:

{if $name?}<p><strong>Имя:<strong>:{$name}</p>{/if}
{if $email?}<p><strong>E-mail:<strong>:{$email}</p>{/if}
{if $pfone?}<p><strong>Телефон:<strong>:{$pfone}</p>{/if}
{if $department?}<p><strong>Тип работы:<strong>:{$department}</p>{/if}
{if $message?}<p><strong>Сообщение:<strong>:{$message}</p>{/if}
{if $attachment?}<p><strong>Файл:<strong>:{$attachment}</p>{/if}

Добавляем в него все поля со всех форм и делаем проверку на заполнение, на почту будет отправлены, только заполненные поля.

Ну и остается лишь только вызвать эту форму в нужном месте.

[[!AjaxForm?
&snippet=`FormIt`
&form=`form-uslugi`
&emailTpl=`tpl-form-uslugi`
&hooks=`spam,email`
&emailSubject=`Сообщение с сайта [[++site_url]]`
&emailTo=`mail@webadaptiv.ru`
&validate=`name:required,email:required`
&validationErrorMessage=`В форме содержатся ошибки!`
&successMessage=`Сообщение успешно отправлено!`
]]

Ну и проверяем работоспособность.

проверяем работоспособность форм

Плюшки

Закрываем модальное окно после отправки формы

Нам нужна кнопка закрытия, в моем случае

<button type="button" class="close" data-dismiss="modal" aria-label="Close">
   <span aria-hidden="true">×</span>
</button>

cм. bootstrap modal.

модальное окно

Так вот нам нужен класс элемента, который закрывает форму при клике, в моем случае это кнопка (buttom) с классом close.

Воспользуемся событием af_complete для клика по этой кнопке.

$(document).on('af_complete', function(event,res) {
	if(res.success) $('.close').click();
});

К стати его нужно прописывать в js файл или подключать в шаблон обвертывая в тег <script> </script>

оборачиваем событие в script

Все теперь после успешной отправки письма, модальное окно автоматически закроется.

Изменение стилей и положения всплывающего окна Ajaxform.

AjaxForm для стилизации окон использует стили jGrowl, которые лежат в assets/components/ajaxform/css/lib/jquery.jgrowl.min.css, можно поправить все прямо там, но если вы обновите компонент, то и стили ваши обновятся на дефолтные, следовательно их лучше предопределить в своем css.

К примеру положение окна по дефолту заданно вот таким стилем

.jGrowl.top-right{top:0;right:0}

те прижато к верху и правой стороне.

Чтобы сменить положение, к примеру по центру, достаточно предопредилить их в своем css, к примеру так:

.jGrowl.top-right{top:40% !important;width:30% !important;left:35% !important}

И точно таким же образом можно изменить весь внешний вид окошко с уведомлением, вот мой конечный код для одного из сайтов:

#jGrowl{font-size:18px;margin:0 12px}
.jGrowl.top-right{left:35%!important;top:35%!important}
#jGrowl .jGrowl-notification{position:relative;width:320px;padding:15px;text-align:center;background:none repeat 0 0 #fff!important;box-shadow:0 0 0 7px #8ab933!important;border:0 solid rgba(255,255,255,0.49)!important}
#jGrowl .jGrowl-notification .jGrowl-close{position:absolute;right:4px;top:4px;color:#8ab933!important}
#jGrowl .jGrowl-notification .jGrowl-message{color:#8ab933!important}

в итоге всплывает вот такое окошко по центру сайт.

новый вид уведомляшки в аякс форм

Оптимизация скорости загрузки сайта. 

  1. Делайте вызов Ajaxform кэшированным (без !).
  2. Объедините стандартные стили и скрипты со своими и укажите в вызове чтобы стандартные не подключались.

Берем CSS код из assets/components/ajaxform/css/lib/jquery.jgrowl.min.css,  assets/components/ajaxform/css/default.css и переносим его в общий файл стилей.

объединяем стили

default.css — из этого файла выкидываем верхнюю строку @import url(‘./lib/jquery.jgrowl.min.css’); — т.к. код мы подключили сразу.

Также берем содержимое файла assets/components/ajaxform/js/default.js и объединяем с основным js файлом.

Далее отключаем css и js в вызове ajaxform.

&frontend_css=«
&frontend_js=«

{'!AjaxForm' | snippet : [
    'snippet' => 'FormIt',
    'form' => 'obr-zvonok',
    'emailTpl' => 'tpl-form',
    'hooks' => 'email,FormItSaveForm',
    'emailFrom' => $_modx->config.emailsender,
    'fromName' => 'Заказ звонка',
	'formFields' => 'name,phone',
	'fieldNames' => 'name==Имя,phone==Телефон',
    'emailSubject' => 'Сообщение с сайта' ~ $_modx->config.site_name,
    'emailTo' => $_modx->config.emailsender,
    'successMessage' => '<p class="h4">Спасибо за обращение в нашу компанию! <br>Менеджер свяжется с вами в ближайшее время</p>',
    'frontend_css' => '',
    'frontend_js' => ''
]}

redirect на другую страницу сайта, после успешной отправки формы?

Добавляем id к форме, если его нет и затем в js файл прописать вот такие строки

$(document).on('af_complete', function(event, response) {
    var form = response.form;
    if (form.attr('id') == 'значение id формы') {
       window.location.href = "[[~id страницы]]"
    }
});

Можно просто обернуть в <script>выше приведенный код</script> и подключить в шаблон с формой ближе к закрытию body.

Настройка отправки целей в AjaxForm

Самый простой и удобный способ настроить цели на AjaxForm это добавить в сообщение успешной отправки script

&successMessage=`Сообщение успешно отправлено
                 <script>ga('send', 'event', 'plea', 'button_ok');
                 yaCounterXXXXXXXX.reachGoal('zayavka');</script>`

Как передать адрес и заголовок страницы

<a href="{$pageId | url}">{$pageId | resource : 'pagetitle'}</a>

Если полный адрес не выводится, попробуйте так

<a href="{$pageId | url : ['scheme' => 'full']}">{$pageId | resource : 'pagetitle'}</a>

Чекбокс — согласие с политикой обработки персональных данных

<div class="checkbox">
    <label>
      <input type="checkbox" required checked> Согласен на <a href="/polici" target="_blank">обработку персональных данных</a>
    </label>
</div>

Дополнительно

Сохранение форм в админке, добавление маски ввода для телефона, email, даты идентично formit.

Смотрите также:

Google reCAPTCHA(v2) для FormIt и AjaxForm

Как в MODX Revo избавиться от спама с FormIt, AjaxForm (без капч)

MODX CSRFHelper — защита форм FormIt и AjaxForm от CSRF атак.

В следующем уроке сделаем хлебные крошки — чтобы наш шаблон выглядел как оригинал.

Cниппет для отправки любых форм через ajax. По умолчанию рассчитан на работу с FormIt, но можно использовать и собственный сниппет.

  • Регистрирует нужные скрипты на фронтенде: jQuery.Form и jQuery.jGrowl.
  • Сохраняет в сессию $scriptProperties при вызове сниппета.
  • Выводит указанную форму, прописывая класс ajax_form и скрытый input для получения $scriptProperties.
  • Вешает обработчик на форму, чтобы она отправлялась через ajax.
  • При отправке запускает указанный сниппет для обработки и возвращает ответ от него.
  • Выводит сообщение об успехе, или ошибки, если есть.

Параметры сниппета

Имя По умолчанию Плейсхолдеры
&form tpl.AjaxForm.example Образец чанка с формой, которую нужно обработать.
&snippet FormIt Сниппет для обработки формы.
&frontend_css [[+assetsUrl]]css/default.css Стили оформления формы и полей с ошибками
&frontend_js [[+assetsUrl]]js/default.js Javascript для отправки формы через ajax
&actionUrl [[+assetsUrl]]action.php Адрес коннектора, на который отправляется форма

Всё, что вы указываете AjaxForm, будет передано в вызываемый сниппет.

Обработка своим сниппетом

Вы можете использовать собственный сниппет, вместо FormIt, который будет делать что угодно (хоть создавать страницы на сайте).
Единственное требование — он обязательно должен возвращать JSON массив с ключами:

  • status — 1 или 0, то есть успех или ошибка.
  • message — сообщение о работе сниппета, выводится если status = 0.
  • data — массив для полей с ошибками, в котором ключами является имя поля, а значением — сообщение об ошибке.

Для удобства работы в параметры сниппета передаётся переменная $AjaxForm с классом компонента, чтобы вы могли вызывать из него методы error и success при выдаче ответа.

Простейший пример своего сниппета:

<?php
if (empty($_POST['name'])) {
    return $AjaxForm->error('Ошибки в форме', array(
        'name' => 'Вы не заполнили имя'
    ));
}
else {
    return $AjaxForm->success('Форма прошла проверку');
}

Вызываем так:

[[!AjaxForm?
    &snippet=`MySnippet`
    &form=`tpl.AjaxForm.example`
]]

Этот сниппет ничего не делает, просто возвращает результат проверки имени.

Валидация формы

Сервер может вернуть ошибку отправки формы и массив полей, не прошедших проверку.
Этим полям автоматически будет добавлен CSS класс error, который убирается при последующей отправке.

Так же вы можете запретить отправку формы, используя javascript переменную afValidated — если она объявлена и равна false, то форма не будет отправлена.

Обратите внимание, что все проверки на javascript можно обойти, так что эту переменную стоит использовать только для удобства пользователей, а не для реальной проверки данных.

<script type="text/javascript">
$(document).on('submit', '.ajax_form', function() {
    // Здесь любой код для проверки формы при отправке
    // Я просто печатаю её в консоли бразуреа
    console.log(this);

    // Результатом работы будет выставление глобальной переменной
    afValidated = false; // Или true, если валидация пройдена
});
</script>

[[!AjaxForm]]

Событие af_complete

При получении ответа от сервера вызывается событие af_complete, которое вы можете использовать для обновления содержимого страницы или другой операции javascript.

Вам просто нужно указать функцию, в которую будет передано событие javascript и объект с ответом от сервера. Обратите внимание, что внутри этого объекта есть и отправляющая форма.

$(document).on('af_complete', function(event, response) {
    var form = response.form;
    // Если у формы определённый id
    if (form.attr('id') == 'my_form_3') {
        // Скрываем её!
        form.hide();
    }
    // Иначе печатаем в консоль весь ответ
    else {
        console.log(response)
    }
});

redirect на другую страницу сайта, после успешной отправки формы?

Добавляем id к форме, если его нет и затем в js файл прописать вот такие строки

$(document).on('af_complete', function(event, response) {
    var form = response.form;
    if (form.attr('id') == 'значение id формы') {
       window.location.href = "[[~id страницы]]"
    }
});

Можно просто обернуть в <script>выше приведенный код</script> и подключить в шаблон с формой ближе к закрытию body.

Всплывающие сообщения

По умолчанию AjaxForm выводит сообщения об успешной отправке формы или о наличии ошибок.
Вы можете самостоятельно вызывать их для своих целей:

AjaxForm.Message.success('Зеленый popup');
AjaxForm.Message.error('Красный popup', 1);
AjaxForm.Message.info('Черный popup');

Вторым параметром можно указать «прилипающий» popup — его нужно будет закрыть вручную, бывает полезно для показа серьёзных ошибок.

То есть, просто вызвав сниппет на странице, вы получаете подключенный jQuery.jGrowl и можете показывать приятные всплывающие уведомления на javascript.

Примеры

Отправка email сообщения при помощи FormIt с требованием некоторых полей:

[[!AjaxForm?
    &snippet=`FormIt`
    &form=`tpl.AjaxForm.example`
    &hooks=`email`
    &emailSubject=`Тестовое сообщение`
    &emailTo=`info@domain.com`
    &validate=`name:required,email:required,message:required`
    &validationErrorMessage=`В форме содержатся ошибки!`
    &successMessage=`Сообщение успешно отправлено`
]]

Отладка

При возникновении любых проблем, в первую очередь проверяйте, отправляется ли форма без AjaxForm.
Помните, что AjaxForm — сниппет-обёртка, он не отправляет письма и не проводит проверку формы. Это делает ваш сниппет или FormIt.

Так же не забывайте заглядывать в консоль браузера на предмет ошибок javascript.
Если сервер выдаёт ошибку 500 при отправке, проверьте параметр register_globals у вашего PHP — он должен быть отключен.

Здравствуйте!
Я пытаюсь отправить сообщение с сайта на почту. Но сообщение не отправляется, в логе браузера выводится ошибка:
VM1036 jquery.form.min.js:7 Uncaught TypeError: Cannot read property ‘success’ of undefined
at w.fn.init.e.fn.ajaxSubmit (VM1036 jquery.form.min.js:7)
at HTMLFormElement. (VM1034 default.js:16)
at HTMLDocument.dispatch (VM1031 jquery-3.3.1.slim.min.js:2)
at HTMLDocument.v.handle (VM1031 jquery-3.3.1.slim.min.js:2)

Код чанка ajaxForm:

<form action="#" method="post" class="ajax_form af_example">
  <div class="form-group">
    <span class="error_name"></span>
    <input type="text" class="form-control" placeholder="Ваше имя" name="name" value="">
  </div>
  <div class="form-group">
    <span class="error_email"></span>
    <input type="email" class="form-control" placeholder="Email" name="email" value="">
  </div>
  <div class="form-group">
    <span class="error_message"></span>
    <textarea class="form-control" rows="3" placeholder="Сообщение" name="message" value=""></textarea>
  </div>
  <button type="submit" class="btn btn-primary btn-block" value="Отправить">Отправить</button>
  [[+fi.success:is=`1`:then=`
    <div class="alert alert-success">[[+fi.successMessage]]</div>
    `]]
    [[+fi.validation_error:is=`1`:then=`
    <div class="alert alert-danger">[[+fi.validation_error_message]]</div>
    `]]
</form>

Код вызова ajaxForm

[[!AjaxForm?
              &snippet=`FormIt`
              &form=`ajaxForm`
              &emailTpl=`email_tpl`
              &hooks=`email`
              &emailSubject=`Сообщение`
              &emailTo=`email@mail.ru`
              &emailFrom=`email@mail.ru`
              &validate=`name:minlength=^2^,email:email:required,message:required`
              &validationErrorMessage=`В форме содержатся ошибки!`
              &successMessage=`Сообщение успешно отправлено`
            ]]

Код чанка email_tpl

<h3>Сообщение</h3>
От кого: [[+name]] <br>
Email: [[+email]] <br>
Текст сообщения: [[+message]]

В начале страницы я подключаю следующие скрипты:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>

Подскажите, пожалуйста, как решить данную проблему?

    • 54370

    • 5 Posts
    • Send PM

    Здравствуйте!
    Подскажите, пожалуйста, в чем моя ошибка. Не работает AjaxForm.
    Чанк формы:

    <form action="" method="post" class="ajax_form af_example">
    	<div class="book">
    		<div class="book-row">
    			<div class="book-row-col">
    				<p><span class="book-lbl">ЗАЕЗД</span> </p>
    				<p><input id="enter" type="text" name="enter" value="[[+fi.enter]]" class="datepicker"/></p>			
    				<p><span class="book-lbl">ФИО</span> </p>
    				<p><input id="fio" type="text" name="fio" value="[[+fi.fio]]" class="standart-input"/></p>
    				<p><span class="book-lbl">Email</span> </p>
    				<p><input id="email" type="text" name="email" value="[[+fi.email]]" class="standart-input"/></p>	
    			</div>
    			<div class="book-row-col">
    				<p><span class="book-lbl">ВЫЕЗД</span> </p>
    				<p><input id="out" type="text" name="out" value="[[+fi.out]]" class="datepicker"/></p>
    				<p><span class="book-lbl">Телефон</span> </p>
    				<p><input id="phone" type="text" name="phone" value="[[+fi.phone]]" class="standart-input"/></p>
    				<p><span class="book-lbl">Номер</span> </p>
    				<p>
    					<select id="room" name="room" type="text"/>
    						<option value="double" [[!+fi.room:FormItIsSelected=`double`]]>Дабл</option>
    						<option value="twin" [[!+fi.room:FormItIsSelected=`twin`]]>Твин</option>
    						<option value="tripple" [[!+fi.room:FormItIsSelected=`tripple`]]>3-местный</option>
    						<option value="pkdouble" [[!+fi.room:FormItIsSelected=`pkdouble`]]>ПК Дабл</option>
    						<option value="pktwin" [[!+fi.room:FormItIsSelected=`pktwin`]]>ПК Твин</option>
    						<option value="luxe" [[!+fi.room:FormItIsSelected=`luxe`]]>Люкс</option>
    						<option value="studio" [[!+fi.room:FormItIsSelected=`studio`]]>Студия</option>
    					</select>
    				</p>	
    			</div>
    		</div>
    		<button type="submit" class="btn btn-primary">[[%af_submit]]</button>
    	</div>
    </form>	
    

    Чанк Email:

    <h3>Сообщение</h3>
    <p>От кого: [[+fio]]</p>
    <p>Заезд: [[+enter]]</p>
    <p>Выезд: [[+out]]</p>
    <p>E-mail: [[+email]]</p>
    <p>Телефон: [[+phone]]</p>
    <p>Номер: [[+room]]</p>
    

    Вызов сниппета:

    [[AjaxForm? 
    &snippet=`FormIt` 
    &form=`book` 
    &emailTpl=`email` 
    &hooks=`email` 
    &emailSubject=`Тестовое сообщение` 
    &emailTo=`shutruk@gmail.com` 
    &successMessage=`Сообщение успешно отправлено` 
    &validate=`name:required,email:required ` 
    &validationErrorMessage=`В форме содержатся ошибки!` ]]
    

    При нажатии выдает сообщение об успешной отправке, но письма не приходят.
    CSS не прилагаю, так как это не имеет отношения к сниппету.
    Буду благодарен за любую помощь. Хотел бы знать, что не так заполнено.
    Заранее спасибо!

      • 44064

      • 185 Posts
      • Send PM

      Здравствуйте!
      Что в логе MODX, нет ли ошибок? Смотрели ли в конслоль браузера, все ли хорошо там? Далее — что возвращает сервер после отправки через ajax? Отправлялись ли письма ранее? Какой у вас хостер, нет ли пожелания от него использовать SMTP для отправки? Если есть сомнения в отправке как таковой попробуйте для начала компонент QuickEmail, отправит ли он тестовое письмо и какой результат?

        Anton Tarasov
        MODX Developer

        Email: contact@antontarasov.com
        Web: antontarasov.com

        • 54370

        • 5 Posts
        • Send PM

        Quote from: himurovi4 at Aug 05, 2018, 08:09 AM

        Здравствуйте!
        Что в логе MODX, нет ли ошибок? Смотрели ли в конслоль браузера, все ли хорошо там? Далее — что возвращает сервер после отправки через ajax? Отправлялись ли письма ранее? Какой у вас хостер, нет ли пожелания от него использовать SMTP для отправки? Если есть сомнения в отправке как таковой попробуйте для начала компонент QuickEmail, отправит ли он тестовое письмо и какой результат?

        В консоли пусто, в журнале ошибок MODX ничего нет. Насчет хостера также проверял. При использовании штатной формы, которая поставляется вместе с AjaxForm (чанк tpl.AjaxForm.example), письмо отправляется.
        Значит, ошибка в моем коде, скорее всего, в коде чанка «book».
        Я не нашел документации, как заполнять плейсхолдеры для разных полей, а в моей форме их шесть.
        Можно ли использовать такие слова:
        [[+fi.enter]]
        [[+fi.fio]]
        [[+fi.room]]

        ???

          • 44064

          • 185 Posts
          • Send PM

          Quote from: butcher at Aug 05, 2018, 09:18 AM

          При использовании штатной формы, которая поставляется вместе с AjaxForm (чанк tpl.AjaxForm.example), письмо отправляется.

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

            Anton Tarasov
            MODX Developer

            Email: contact@antontarasov.com
            Web: antontarasov.com

            • 54370

            • 5 Posts
            • Send PM

            Quote from: himurovi4 at Aug 05, 2018, 03:19 PM

            Quote from: butcher at Aug 05, 2018, 09:18 AM

            При использовании штатной формы, которая поставляется вместе с AjaxForm (чанк tpl.AjaxForm.example), письмо отправляется.

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

            НИЧЕГО НЕ ПОНИМАЮ!!!
            Сейчас начало работать. Все, как я хотел.
            Самое интересное, уже не помню, что делал!
            Набирал заново вызов формы и что-то в чанке.
            Говорят, MODX не любит пробелы.
            В-общем, сейчас все работает.
            Спасибо всем!!!

              • 44064

              • 185 Posts
              • Send PM

              Quote from: butcher at Aug 05, 2018, 04:19 PM

              НИЧЕГО НЕ ПОНИМАЮ!!!
              Сейчас начало работать. Все, как я хотел.
              Самое интересное, уже не помню, что делал!
              Набирал заново вызов формы и что-то в чанке.
              Говорят, MODX не любит пробелы.
              В-общем, сейчас все работает.
              Спасибо всем!!!

              Привыкайте, иногда по невниманию, по усталости именно так и случается..где-то пробел, кавычка не та, или символ не тот..и часами ходишь вокруг да около. Полезно посмотреть некоторое время спустя свежей головой и под другим углом))

                Anton Tarasov
                MODX Developer

                Email: contact@antontarasov.com
                Web: antontarasov.com

              При отправке письма через AjaxForm с FormIt не приходят письма, хотя сообщение удачной отправки есть, в базу письмо не сохранятся.

              [[!AjaxForm? 
              &form=`contact_form` 
              &snippet=`FormIt` 
              &hooks=`FormitSaveForm,email`
              &emailSubject=`Сообщение с нашего сайта`
              &emailTo=`veterangrupp@mail.ru`
              &emailFrom=`veterangrupp@mail.ru`
              &emailTpl=`tpl.email`
              &validate=`name:minLength=^2^,email:email:required,message:minLength=^10^,g-recaptcha-response:required`
              &validationErrorMessage=`В форме содержатся ошибки!`
              &successMessage=`Сообщение успешно отправлено`
              ]]
              
              
              <form action="" method="post" class="ajax_form af_example">
              
                  <div class="form-group">
                      <label class="control-label" for="af_name">[[%af_label_name]]</label>
                      <div class="controls">
                          <input type="text" id="af_name" name="name" value="[[+fi.name]]" placeholder="" class="form-control"/>
                          <span class="error_name">[[+fi.error.name]]</span>
                      </div>
                  </div>
              
                  <div class="form-group">
                      <label class="control-label" for="af_email">[[%af_label_email]]</label>
                      <div class="controls">
                          <input type="email" id="af_email" name="email" value="[[+fi.email]]" placeholder="" class="form-control"/>
                          <span class="error_email">[[+fi.error.email]]</span>
                      </div>
                  </div>
              
                  <div class="form-group">
                      <label class="control-label" for="af_message">[[%af_label_message]]</label>
                      <div class="controls">
                          <textarea id="af_message" name="message" class="form-control" rows="5">[[+fi.message]]</textarea>
                          <span class="error_message">[[+fi.error.message]]</span>
                      </div>
                  </div>
              
                  <div class="form-group">
                      <div class="controls">
                          <button type="reset" class="btn btn-default">[[%af_reset]]</button>
                          <button type="submit" class="btn btn-primary">[[%af_submit]]</button>
                      </div>
                  </div>
              
                  [[+fi.success:is=`1`:then=`
                  <div class="alert alert-success">[[+fi.successMessage]]</div>
                  `]]
                  [[+fi.validation_error:is=`1`:then=`
                  <div class="alert alert-danger">[[+fi.validation_error_message]]</div>
                  `]]
              </form>
              
              <h3>Сообщение</h3>
              <p>С Сайта: [[++site_name]]</p>
              <p>От кого: [[+name]]</p>
              <p>E-mail: [[+email]]</p>
              <p>Сообщение: [[+message]]</p>

              задан 26 ноя 2017 в 14:15

              nikolay.akhmetyanov's user avatar

              Поменяйте местами хуки вот так &hooks=`email,FormitSaveForm
              В Formit hooks выполняется последовательно.

              Так же в параметре &validate уберите g-recaptcha-response:required, если вы не используете Google Recaptcha. Если вам нужна capta то нужно подключить соответствующий хук и настроить его.

              ответ дан 14 дек 2017 в 8:47

              Fapalz's user avatar

              FapalzFapalz

              931 серебряный знак9 бронзовых знаков

              Как вариант, попробуйте просто Formit(AjaxForm есть обертка для него) запустить с учетом корректировок от Fapalz.
              Если не поможет, подиагностируйте отправку и доставку писем при помощи компонента QuickEmail

              ответ дан 21 фев 2020 в 10:34

              Anton Tarasov's user avatar

              Anton TarasovAnton Tarasov

              5941 золотой знак3 серебряных знака11 бронзовых знаков

              В этой статье рассмотрим процесс создания формы обратной связи на MODX с использованием FormIt. А также работу с ней через Ajax посредством AjaxForm.

              В репозитории MODX имеется очень популярное дополнение для динамической обработки форм. Называется оно FormIt.

              Это дополнение используется для обработки формы после нажатия на кнопку отправки. FormIt сначала выполняет валидацию, и только затем (после успешной проверки) другие действия. Например, такие как отправка сообщения на электронную почту, сохранение данных формы в базу данных, функцию автоответчика и др.

              Установить пакет FormIt можно из главного репозитория modx.com/extras/package/formit.

              Установка пакета FormIt для MODX

              Пример простой формы обратной связи на FormIt

              В этом примере создадим простую HTML форму с использованием Bootstrap 5. Она будет состоять из 3 полей: имя, email и сообщение. FormIt будет выполнять валидацию формы и отправлять сообщение с данными, которые ввел пользователь, на email.

              Вид формы обратной связи на FormIt для MODX сайта

              Вызов сниппета FormIt:

              [[!FormIt?
                &emailFrom=`[[++emailsender]]`
                &emailTo=`alexander@mail.com`
                &emailTpl=`myEmailTpl`
                &hooks=`email`
                &submitVar=`feedback-form`
                &successMessage=`Форма успешно отправлена!`
                &validate=`nospam:blank,
                  name:required,
                  email:email:required,
                  message:required:minLength=^20^`
              ]]

              Список используемых параметров:

              • hooks – список скриптов, которые нужно выполнить после успешной валидации формы; скрипты будут запускаться последовательно друг за другом; если какой-то скрипт завершится не удачно, то следующие за ним выполняться не будут;
              • validate – список полей, которые нужно проверить на соответствии указанным требованиям; можно указать несколько валидаторов, например, как это сделано для email;
              • submitVar – необходим, чтобы этот вызов сниппета FormIt обрабатывал не все формы, а только те, которые содержат указанный ключ в составе передаваемых на сервер данных (в суперглобальном массиве $_POST);
              • successMessage – сообщение, которое необходимо вывести после успешного завершения обработки формы; работает, только если не используется свойство для редиректа;
              • emailTpl – чанк, содержащий шаблон email письма;
              • emailTo – адрес, на который нужно отправить email;
              • emailFrom – адрес, от которого будет отправлен email; в этом примере email будем брать из системного параметра emailsender;
              • emailSubject – тема письма.
              • validationErrorMessage – сообщение, которое нужно вывести, если в форме содержатся ошибки.

              Работает FormIt следующим образом:

              1. Получает данные формы. Так как в вызове сниппета FormIt, мы указали свойство submitVar, то этот сниппет будет обрабатывать только ту форму, которая будет передавать в теле запроса этот ключ. Его мы добавили к кнопке type="submit".

              2. Выполняет валидацию. После этого выполняется валидация формы в соответствии с требованиями, которые мы указали в свойстве validate. Валидатор в этом свойстве задаётся через двоеточие.

              Валидатор blank проверяет, является ли поле пустым. В данном примере мы проверяем с помощью него поле nospam:

              nospam:blank

              Кроме blank в этом примере ещё используются следующие валидаторы:

              • required – проверяет, является ли поле не пустым;
              • email – содержит ли поле корректный адрес электронной почты;
              • minLength – требование, к минимальному количеству символов.

              Например, для проверки поля email мы используем 2 валидатора:

              email:email:required

              Таким образом это поле должно быть не пустым и содержать корректный email.

              Если какие-то поля не прошли валидацию, то ошибки будут выведены в соответствующие плейсхолдеры. Например, для поля email это будет:

              [[+fi.error.email]]

              Отображение ошибок валидации формы на FormIt для MODX сайта

              3. Выполнение хуков. После успешной валидации будут последовательно друг за другом выполнены скрипты, указанные в hooks.

              В приведённом примере мы используем в hooks только один скрипт: email. Он отправит форму на email. Шаблон для этого письма он возьмёт из чанка, заданного в emailTpl. А отправит он письмо на email, указанный в свойстве emailTo.

              Сообщение отправленное на email с использованием FormIt для MODX сайта

              4. Вывод сообщения об успехе. После успешного завершения хука email будет выведено в плейсхолдер fi.successMessage сообщение, указанное в свойстве successMessage.

              Сообщение об успешной отправки формы на FormIt для MODX сайта

              HTML код формы:

              [[!+fi.successMessage:notempty=`<div class="alert alert-success" role="alert">[[!+fi.successMessage]]</div>`]]
              <form action="[[~[[*id]]]]" method="post" class="form">
                <input type="hidden" name="nospam" id="nospam" value="">
                <div class="mb-3">
                  <label for="name" class="form-label">Name</label>
                  <input type="text" class="form-control[[!+fi.error.name:notempty=` is-invalid`]]" name="name" id="name" value="[[!+fi.name]]">
                  <div class="invalid-feedback">[[!+fi.error.name]]</div>
                </div>
                <div class="mb-3">
                  <label for="email" class="form-label">Email</label>
                  <input type="email" class="form-control[[!+fi.error.email:notempty=` is-invalid`]]" name="email" id="email" value="[[!+fi.email]]">
                  <div class="invalid-feedback">[[!+fi.error.email]]</div>
                </div>
                <div class="mb-3">
                  <label for="phone" class="form-label">Phone</label>
                  <input type="tel" class="form-control[[!+fi.error.phone:notempty=` is-invalid`]]" name="phone" id="phone"
                      value="[[!+fi.phone]]">
                  <div class="invalid-feedback">[[!+fi.error.phone]]</div>
                </div>
                <div class="mb-3">
                  <label for="message" class="form-label">Message</label>
                  <textarea class="form-control[[!+fi.error.message:notempty=` is-invalid`]]" name="message" id="message"
                      rows="5">[[!+fi.message]]</textarea>
                  <div class="invalid-feedback">[[!+fi.error.message]]</div>
                </div>
                <div class="mb-3">
                  <input type="submit" class="btn btn-primary" name="feedback-form" value="Отправить">
                </div>
              </form>

              Оформление формы выполнено на Bootstrap 5.

              Скрытое поле nospam используется для защиты от спама. Обычно спам боты пытаются заполнить все поля, а это поле должно быть пустым. Если поле nospam не пустое, то форма не пройдёт проверку и её дальнейшая обработка выполняться не будет.

              Сниппет FormIt будет заполнять в форме заданные плейсхолдеры. Например, для поля email:

              • fi.email – значением поля email;
              • fi.error.email – сообщением об ошибке при валидации.

              Выделение полей, которые не прошли валидацию, выполняется посредством добавления к ним класса is-invalid. Например, для поля email это будет выглядеть так:

              [[!+fi.error.email:notempty=` is-invalid`]]

              Т.е. когда плейсхолдер fi.error.email не пустой, у элемента <input> появится класс is-invalid.

              Для вывода сообщения об успешной обработки формы используется следующая конструкция:

              [[!+fi.successMessage:notempty=`<div class="alert alert-success" role="alert">[[!+fi.successMessage]]</div>`]]

              Она работает очень просто: если плейсхолдер fi.successMessage что-то содержит, то выведи HTML блок с содержимым [[!+fi.successMessage]]:

              <div class="alert alert-success" role="alert">[[!+fi.successMessage]]</div>

              Этот HTML блок является компонентом Alert фреймворка Bootstrap.

              В теге <form> для атрибута action укажем URL на эту же страницу:

              <form action="[[~[[*id]]]]" method="post">

              Содержимое чанка myEmailTpl:

              <p style="font-weight: bold;">Сообщение с формы обратной связи.</p>
              <p><mark>[[+name]]</mark> (email: <mark>[[+email]]</mark>, phone: <mark>[[+phone:default=`-`]]</mark>) оставил следующее сообщение:</p>
              <p style="background-color: #eee; padding: 15px;">[[+message]]</p>

              Отправка формы через AJAX

              По умолчанию FormIt не умеет работать с формой через AJAX. Но в репозитории modstore.pro имеется дополнение AjaxForm, которое позволяет отправлять формы через AJAX. По умолчанию оно работает с FormIt. Но при необходимости вместо FormIt можно использовать собственный сниппет.

              При использовании AjaxForm работа с формой будет осуществляться следующим образом:

              1. вывод HTML формы будет осуществляться из чанка, который передан AjaxForm в свойстве form;
              2. отправка форма выполняется через AJAX, для этого сниппет AjaxForm регистрирует на фронтенде нужные скрипты;
              3. на сервере запускает сниппет FormIt и передаёт ему данные формы;
              4. после получения ответа от FormIt передаёт его браузеру, который выводится пользователю на страницу с использованием JavaScript.

              Перед тем как начать переделывать форму проверим установлено ли у нас расширение AjaxForm.

              Установка пакета AjaxForm для MODX

              Ход работы:

              1. Создадим чанк myFormTpl и вставим в него HTML код формы.

              AjaxForm вывод сообщений об ошибках, например, для поля email, осуществляет в элемент с классом error_mail. Кроме этого, к полям, которые не прошли валидацию добавляет класс error.

              Но нас это не устраивает, т.к. сообщения об ошибке нужно помещать в элемент с классом invalid-feedback, а к полям, которые не прошли проверку необходимо добавлять класс is-invalid.

              Это мы будем выполнять с помощью JavaScript при получении ответа от сервера:

              $(document).on('af_complete', function (event, response) {
                const elForm = $(response.form);
                elForm.find('.is-invalid').each(function (index, el) {
                  $(el).removeClass('is-invalid');
                });
                for (let key in response.data) {
                  const elInput = elForm.find(`[name=${key}]`);
                  elInput.addClass('is-invalid');
                  elInput.next('.invalid-feedback').text($(response.data[key]).text());
                }
              });

              После этого из формы необходимо удалить плейсхолдеры [[!+fi.name]], [[!+fi.error.name]] и др. Они используются в качестве заполнителей для сниппета FormIt и позволяют нам сохранять значения, введённые пользователем и отображать ошибки валидации. Но так как сейчас работа ведётся через AJAX, то они нам не нужны.

              В итоге HTML форма будет иметь следующий код:

              <form action="#" method="post" class="feedback-form">
                <input type="hidden" name="nospam" id="nospam">
                <div class="mb-3">
                  <label for="name" class="form-label">Имя</label>
                  <input type="text" class="form-control" name="name" id="name">
                  <div class="invalid-feedback"></div>
                </div>
                <div class="mb-3">
                  <label for="email" class="form-label">Email</label>
                  <input type="email" class="form-control" name="email" id="email">
                  <div class="invalid-feedback"></div>
                </div>
                <div class="mb-3">
                  <label for="message" class="form-label">Сообщение</label>
                  <textarea class="form-control" name="message" id="message" rows="3"></textarea>
                  <div class="invalid-feedback"></div>
                </div>
                <div class="mb-3">
                  <input type="submit" class="btn btn-primary" name="feedback-form" value="Отправить">
                </div>
              </form>

              2. Добавим в нужный ресурс или шаблон вызов сниппета AjaxForm и скрипт:

              <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
              [[AjaxForm?
                &form=`myFormTpl`
                &formSelector=`feedback-form`
                &emailTpl=`myEmailTpl`
                &emailTo=`alexander@gmail.com`
                &hooks=`email`
                &successMessage=`Форма успешно отправлена!`
                &validationErrorMessage=`В форме содержатся ошибки!`
                &submitVar=`feedback-form`
                &validate=`nospam:blank,
                  name:required,
                  email:email:required,
                  message:required:minLength=^20^`
              ]]
              <script>
                $(document).on('af_complete', function(event, response) {
                  const elForm = $(response.form);
                  elForm.find('.is-invalid').each(function(index, el) {
                    $(el).removeClass('is-invalid');
                  });
                  for (let key in response.data) {
                    const elInput = elForm.find(`[name=${key}]`);
                    elInput.addClass('is-invalid');
                    elInput.next('.invalid-feedback').text($(response.data[key]).text());
                  }
                });
              </script>

              Свойство form в вызове сниппета AjaxForm указывает чанк, в котором содержится HTML форма. Остальные свойства данный сниппет просто передаёт FormIt.

              Скрипт необходим для установки не валидным полям класса is-invalid и вставки сведений об ошибках в элементы .invalid-feedback. Кроме этого JavaScript файлы, которые регистрирует AjaxForm во фронтенде, написаны с использованием библиотеки jQuery. Поэтому её нужно подключить.

              Дополнительно

              1. Редирект на другую страницу после успешной обработки формы.

              Перенаправить пользователя на другую страницу после успешной отправки формы можно с помощью хука redirect:

              &hooks=`email,redirect`
              &redirectTo=`7`

              Указание ресурса, на который необходимо перенаправить пользователя осуществляется с помощью свойства redirectTo. В данном примере пользователь будет перенаправлен на ресурс, который имеет в качестве id значение 7.

              2. Сохранение данных формы в базу данных.

              Сохранить отправленные формы в базу данных можно с помощью хука FormItSaveForm:

              &hooks=`email,FormItSaveForm`
              &formName=`Форма обратной связи`
              &formFields=`name,email,message`
              &fieldNames=`name==Имя,email==Email,message==Сообщение`

              Диалоговое окно для просмотра всех отправленных форм в админке MODX

              Свойства:

              • formName – название формы. По умолчанию: "form-{resourceid}";
              • formFields – список полей, которые следует сохранить. По умолчанию: все поля, включая кнопку submit;
              • fieldNames – позволяет задать отображение полей на форме в менеджере.

              3. Добавление в форму заголовка и URL страницы

              Добавить в форму дополнительные данные, например заголовок страницы и её URL, можно с помощью скрытых полей:

              <input type="hidden" name="title" value="[[*pagetitle]]">
              <input type="hidden" name="url" value="[[~[[*id]]? &scheme=`full`]]">

              Для отправки этой информации на email добавьте в шаблон письма:

              <p>Страница, с которой отправлена форма: <a href="[[+url]]">[[+title]]</a></p>

              4. Обработка полей select

              Для обработки <select> FormIt предоставляет фильтр вывода FormItIsSelected. Он устанавливает атрибут selected, если значение <option> соответствует выбранной:

              <div class="mb-3">
                <label for="color" class="form-label">Цвет</label>
                <select class="form-select[[!+fi.error.color:notempty=` is-invalid`]]" name="color" id="color" value="[[!+fi.color]]">
                  <option value="" selected disabled>Выберите цвет</option>
                  <option value="Красный" [[!+fi.color:FormItIsSelected=`Красный`]]>Красный</option>
                  <option value="Оранжевый" [[!+fi.color:FormItIsSelected=`Оранжевый`]]>Оранжевый</option>
                  <option value="Желтый" [[!+fi.color:FormItIsSelected=`Желтый`]]>Желтый</option>
                </select>
                <div class="invalid-feedback">[[!+fi.error.color]]</div>
              </div>

              Обработка поля формы select с помощью FormIt для сайта на MODX

              5. Обработка чекбоксов и радиокнопок

              FormIt для обработки type="checkbox" и type="radio" предоставляет фильтр FormItIsChecked аналогичный FormItIsSelected.

              Это пример с чекбоксами:

              <div class="mb-3">
                <div class="form-check">
                  <input type="checkbox" class="form-check-input [[!+fi.error.colors:notempty=` is-invalid`]]" name="colors[]" id="colors-red" value="Красный" [[!+fi.colors:FormItIsChecked=`Красный`]]>
                  <label class="form-check-label" for="colors-red">Красный</label>
                </div>
                <div class="form-check">
                  <input type="checkbox" class="form-check-input [[!+fi.error.colors:notempty=` is-invalid`]]" name="colors[]" id="colors-orange" value="Оранжевый" [[!+fi.colors:FormItIsChecked=`Оранжевый`]]>
                  <label class="form-check-label" for="colors-orange">Оранжевый</label>
                </div>
                <div class="form-check">
                  <input type="checkbox" class="form-check-input [[!+fi.error.colors:notempty=` is-invalid`]]" name="colors[]" id="colors-yellow" value="Желтый" [[!+fi.colors:FormItIsChecked=`Желтый`]]>
                  <label class="form-check-label" for="colors-yellow">Желтый</label>
                </div>
                <input type="hidden" class="[[!+fi.error.colors:notempty=` is-invalid`]]" name="colors[]" value="">
                <div class="invalid-feedback">[[!+fi.error.colors]]</div>
              </div>

              Если colors должно быть обязательным, то нужно добавить «скрытое» поле, как это показано в примере выше. После этого в свойство validate добавить colors:required:

              [[!FormIt?
                ...
                &validate=`...
                  colors:required`
              ]]

              Обработка checkbox полей формы с помощью FormIt для сайта на MODX

              Сниппет работает просто:

              1. Регистрирует нужные скрипты на фронтенде (jQuery.Form и jQuery.jGrowl)
              2. Сохраняет в сессию $scriptProperties при вызове сниппета
              3. Выводит указанную форму, прописывая класс ajax_form и скрытый input для поучения $scriptProperties
              4. Вешает обработчик на форму, чтобы она отправлялась через ajax
              5. При отправке запускает указанный сниппет для обработки и возвращает ответ от него
              6. Выводит сообщение об успехе, или ошибки, если есть

              По умолчанию все рассчитано на работу с FormIt, но можно указать и собственный сниппет.

              Пример вызова для FormIt:

              [[!AjaxForm?
              	&snippet=`FormIt`
              	&form=`tpl.AjaxForm.example`
              	&hooks=`email`
              	&emailSubject=`Тестовое сообщение`
              	&emailTo=`info@domain.com`
              	&validate=`name:required,email:required,message:required`
              	&validationErrorMessage=`В форме содержатся ошибки!`
              	&successMessage=`Сообщение успешно отправлено`
              ]]

              Для вывода сообщений об ошибке заполнения поля, скрипт ищет в форме блок с классом error_имяполя и вставляет в него сообщение (см. дефолтный чанк).
              При повторной отправке формы эти сообщения удаляются.

              По идее, можно менять все вызовы FormIt на рабочих сайтах, просто оборачивая их в AjaxSubmit и перенося форму со страницы в чанк — должно работать.

              Конечно вы можете использовать и собственный сниппет, который будет делать что угодно (хоть создавать страницы на сайте) и должен возвращать JSON массив с ключами:

              • status — 1 или 0, то есть успех или ошибка
              • message — сообщение о работе сниппета
              • data — массив для полей с ошибками, в котором ключами является имя поля, а значением — сообщение об ошибке

              Для удобства работы в параметры сниппета передаётся переменная $AjaxForm с классом компонента. Советую вызывать из него методы error и success при выдаче ответа.

              Простейший пример своего сниппета:

              if (empty($_POST['name'])) {
              	return $AjaxForm->error('Ошибки в форме', array('name' => 'Вы не заполнили имя'));
              }
              else {
              	return $AjaxForm->success('Форма прошла проверку');
              }

              Вызываем так:

              [[!AjaxSubmit?
              	&snippet=`MySnippet`
              	&form=`tpl.AjaxForm.example`
              ]]

              Кстати

              Сниппет можно использовать еще одним интересным образом — просто вызвав его на странице, вы получаете подключенный jQuery.jGrowl и можете легко показывать приятные всплывающие уведомления на javascript:

              AjaxForm.Message.success('Зеленый popup');
              AjaxForm.Message.error('Красный popup', 1);
              AjaxForm.Message.info('Черный popup');

              Вторым параметром можно указать «прилипающий» popup — его нужно будет закрыть вручную, бывает полезно для показа серьёзных ошибок.

              Сниппет использует:

              • jQuery.Form для отправки формы через ajax.
              • jQuery.jGrowl для вывода сообщений

              Исходный код находится на GitHub

              Понравилась статья? Поделить с друзьями:
            • Modx 500 ошибка после переноса
            • Modulenotfounderror python как исправить
            • Modulenotfounderror no module named pygame ошибка
            • Module set response error status
            • Module object is not callable python ошибка