RSS-подписка

RSS-лента

Новые статьи

Последние комментарии


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

Ваш e-mail:

Рассылка новостей от Loco

Yii2: Выводим модальное окно с формой обратной связи и отправляем её Ajax'ом на email

Yii2: Выводим модальное окно с формой обратной связи и отправляем её Ajax'ом на email Делаем форму обратной связи в модальном окне, с Ajax-валидацией и отправкой данных формы администратору на email.

Некогда мы выводили модальное окно с формой обратной связи на CJuiDialog для Yii 1. Делаем то же теперь в Yii 2. Но теперь используем Bootstrap 3 modal, в целом же вести всплывающую форму отправляющую письмо по ajax, в случае с Yii 2 проще. Это достаточно насущная задача, так как крайне часто требуется на сайте воткнуть кнопку "Оставить онлайн заявку" или "Перезвоните мне".

В работе форму можно посмотреть на сайте нашей школы брейк данса «Inspire».

1) Ставим кнопку, вызывающую модальное окно с формой и само окно (обычно в шаблоне главной страницы)

<p><a class="btn btn-success signup" data-userid="22" >Записаться на занятия</a></p>
<!-- Modal "Записаться на занятия" -->
<div class="modal fade" id="my-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
   <div class="modal-dialog modal-sm">
     <div class="modal-content">
       <div class="modal-body">
         ...
       </div>
     </div><!-- /.modal-content -->
   </div><!-- /.modal-dialog -->
</div><!-- /.modal -->
В теле окна сейчас пусто, значит мы будем наполнять его асинхронно по Ajax.

2) Тут же в шаблоне главной, где подключили кнопку (на весь сайт это не нужно распространять), подключаем скрипт:

<?php
$this->registerJsFile(
    'scripts/index.js',
    ['depends'=>'app\assets\AppAsset']
);
?>

3) Его создадим в папке web/scripts.

$(document).ready(function () {

    $('.signup').click(function(event){ // нажатие на кнопку - выпадает модальное окно
        event.preventDefault();
         

        var url = 'signup';
        var clickedbtn = $(this);
        //var UserID = clickedbtn.data("userid");
         
        var modalContainer = $('#my-modal');
        var modalBody = modalContainer.find('.modal-body');
        modalContainer.modal({show:true});
        $.ajax({
            url: url,
            type: "GET",
            data: {/*'userid':UserID*/},
            success: function (data) {
                $('.modal-body').html(data);
                modalContainer.modal({show:true});
            }
        });
    });
    $(document).on("submit", '.signup-form', function (e) {
        e.preventDefault();
        var form = $(this);
        $.ajax({
            url: "submitsignup",
            type: "POST",
            data: form.serialize(),
            success: function (result) {
                console.log(result);
                var modalContainer = $('#my-modal');
                var modalBody = modalContainer.find('.modal-body');
var insidemodalBody = modalContainer.find('.gb-user-form');

if (result == 'true') {
insidemodalBody.html(result).hide(); // 
 //$('#my-modal').modal('hide');
                 $('#success').html("<div class='alert alert-success'>");
                $('#success > .alert-success').append("<strong>Спасибо! Ваше сообщение отправлено.</strong>");
$('#success > .alert-success').append('</div>');

setTimeout(function() { // скрываем modal через 4 секунды
$("#my-modal").modal('hide');
}, 4000);
                }
                else {
                    modalBody.html(result).hide().fadeIn();
                }
            }
        });
    });

});

Здесь 2 события. Первое выполняется по нажатию кнопки с классом .signup и обращается к URL = "signup", который пропишем дальше в rules у urlManager. Сразу пропишем и для второго события.

'signup'=>'site/signup',
'submitsignup'=>'site/submitsignup',

Вторая функция обрабатывает отправку формы. И если получен ответ true, то выводит сообщение об успешной отправке письма и закрывает модальное окно через 4 секунды (если посетитель сам не закрыл его раньше). Если будет получен не true, а что-то другое, то это покажется в модальном окне, тут делается скрытие и обновление его .hide().fadeIn(). 

4) Едем дальше. В контроллере SiteController методы signup и submitsignup

// Всплывшее модальное окно заполняем представлением signup.php формы с полями
public function actionSignup()
    {
        $model = new \app\models\SignupForm();
        //$model->id =$userid;
        return $this->renderPartial('signup', [
            'model' => $model,
        ]);
    }
    
// По нажатию в модальном окне на Отправить - форма отправляется администратору на почту     
public function actionSubmitsignup()
    {
        $model = new \app\models\SignupForm();
        $model->load(Yii::$app->request->post());
     
        if($model->load(Yii::$app->request->post()) && $model->contact(Yii::$app->params['adminEmail'])) {
        
            //save the password
            $success=true;
            return json_encode($success);
        }
        else
        {
            return $this->renderPartial('signup', [
            'model' => $model,
            ]);
        }
    }

Как раз первый заполняет в модельное окно форму через renderPartial. Второй метод submitsignup похож на contact - он таким же образом эту форму отправляет на email.

5) Создадим модель SignupForm.php (очень похожую на ContactForm)

<?php

namespace app\models;

use Yii;
use yii\base\Model;
use yii\helpers\Security;

class SignupForm extends Model
{
public $name;
public $phone;
public $email;
/**
* Здесь мы указываем правила валидации - они могут быть как стандартными, так и кастомными
*/
public function rules()
{
return [
['name', 'required'],
//[['phone','email'], 'safe'],
[['email'], 'email'],
[['phone', 'email'], 'validatePhoneEmailEmpty', 'skipOnEmpty'=> false],
];
}

    public function attributeLabels()
    {
        return [
'name' => 'Ваше имя',
'email' => 'Email',
'phone' => 'Телефон',
        ];
    }

/* Кастомная функция для проверки, что хотя бы одно из полей email или phone посетитель заполнил */
public function validatePhoneEmailEmpty()
{
if(empty($this->phone) && empty($this->email))
{
$errorMsg= 'Укажите ваш email или телефон';
$this->addError('phone',$errorMsg);
$this->addError('email',$errorMsg);
}
if(!empty($this->phone) && (strlen($this->phone)<7))
{
$errorMsg= 'Слишком мало цифр в номере телефона';
$this->addError('phone',$errorMsg);
}
}

    /**
     * Аналог ContactForm
     */
    public function contact($email)
    {
        if ($this->validate()) {
            Yii::$app->mailer->compose()
                ->setTo($email)
                ->setFrom(['youremail@adress.ru' => $this->name])
                ->setSubject('Заявка на занятия по брейку от '.$this->name)
                ->setTextBody($this->email."\n Телефон: ".$this->phone)
                ->send();

            return true;
        } else {
            return false;
        }
    }
}
Здесь любопытен validatePhoneEmailEmpty - свой валидатор. Обратите внимание на то, что мы подключили его в rules c 'skipOnEmpty'=> false. Это сделано, потому что в Yii2 по умолчанию 'skipOnEmpty'=> true, отчего пустые поля пропускаются и не валидируются проверкой на пустое значение. Долго бился не понимая, почему мой валидатор не срабатывал вообще, пока не выключил этот параметр. (Если понадобится проверять значения на существование в базе данных, то надо смотреть ExistValidator).

 

6) И само представление формы

<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;

/**
 * @var yii\web\View $this
 * @var app\models\gbUser $model
 * @var yii\widgets\ActiveForm $form
 */
?>
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
<div id="success"> </div> <!-- For success message -->

<div class="gb-user-form">

    <?php $form = ActiveForm::begin(['options' => ['class' => 'signup-form']]); ?>

    <?= $form->field($model, 'name')->textInput(['maxlength' => 255], ['class' => 'input-modal']) ?>
    
    <?= $form->field($model, 'phone')->textInput(['maxlength' => 255], ['class' => 'input-modal']) ?>

<?= $form->field($model, 'email')->textInput(['maxlength' => 255], ['class' => 'input-modal']) ?>

    <div class="form-group text-right">
        <?= Html::submitButton('Отправить', ['class' => 'btn btn-success btn-update-password']) ?>
    </div>

    <?php ActiveForm::end(); ?>

</div> 

N.B. Обратите внимание, что письма по-умолчанию отправляются swiftmailer через функцию mail(). Посмотрите в настройках конфига, чтобы на рабочем проекте на сервере был выключен параметр useFileTransport. Это задаётся в настройках компонента mailer (либо закомментруйте строку, либо явно укажите 'useFileTransport' => false,)

'mailer' => [
            'class' => 'yii\swiftmailer\Mailer',
            // send all mails to a file by default. You have to set
            // 'useFileTransport' to false and configure a transport
            // for the mailer to send real emails.
            //'useFileTransport' => true,
        ],

Если этого не сделать, то все письма будут складываться и скапливаться в runtime/mail, а не отправляться адресату:

при включенном параметре useFileTransport true письма остаются в runtime

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

 

P.S. Если кому-то будет интересно, вот как без фреймворков сразу на скриптах - Модальное окно Bootstrap 3 с формой, отправляющей email по Ajax (пригодится, если будете клепать лендинг-страницы без движков).

Сильно помогло:

Источник: loco.ru

almix
Разработчик Loco, автор статей по веб-разработке на Yii, CodeIgniter, MODx и прочих инструментах. Создатель Team Sense.

Вы можете почитать все статьи от almix'а.



Другие статьи по этой теме:

Комментарии (0)     Подпишитесь на RSS комментариев к этой статье.