Пример будет реализован на Yii2 basic, для внедрения его на Yii2 advanced необходимо сменить локацию файлов соответствующую шаблону advanced и namespace (особых трудностей это вызвать не должно).
Устанавливаем Yii2 basic, Как установить Yii 2 basic, краткая инструкция.
Форма обратной связи во всплывающем окне будет работать на каждой странице сайта, поэтому реализуем виджет который будет инициализировать модель ContactForm, отправлять сообщение в случае правильного заполнения формы и сообщать об отправке пользователю (посетителю сайта).
Создаем класс виджет app/components/FBFWidget.php со следующим содержимым:
<?php
namespace app\components;
use Yii;
use yii\base\Widget;
use app\models\ContactForm;
class FBFWidget extends Widget
{
public function run()
{
$model = new ContactForm();
if ($model->load(Yii::$app->request->post()) && $model->contact(Yii::$app->params['adminEmail'])) {
Yii::$app->session->setFlash('contactFormSubmitted');
}
return $this->render('fbfWidget', [
'model' => $model,
]);
}
}
Содержимое класса виджета FBFWidget - простой виджет с кодом инициализации, проверки и отправки формы обратной связи, код практически идентичен содержанию метода (экшена) actionContact класса (контроллера) SiteController (app/controllers/SiteController.php).
Далее создадим представление (view) для виджета app/components/views/fbfWidget.php:
<?php
use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use yii\captcha\Captcha;
?>
<?php if (Yii::$app->session->hasFlash('contactFormSubmitted')) { ?>
<?php
$this->registerJs(
"$('#myModalSendOk').modal('show');",
yii\web\View::POS_READY
);
?>
<!-- Modal -->
<div class="modal fade" id="myModalSendOk" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Feedback form</h4>
</div>
<div class="modal-body">
<p>Thank you for contacting us. We will respond to you as soon as possible.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<?php } ?>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<?php $form = ActiveForm::begin(['id' => 'contact-form']); ?>
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Feedback form</h4>
</div>
<div class="modal-body">
<?= $form->field($model, 'name')->textInput(['autofocus' => true]) ?>
<?= $form->field($model, 'email') ?>
<?= $form->field($model, 'subject') ?>
<?= $form->field($model, 'body')->textarea(['rows' => 6]) ?>
<?= $form->field($model, 'verifyCode')->widget(Captcha::className(), [
'template' => '<div class="row"><div class="col-lg-3">{image}</div><div class="col-lg-6">{input}</div></div>',
]) ?>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<?= Html::submitButton('Submit', ['class' => 'btn btn-primary', 'name' => 'contact-button']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
</div>
</div>
Представление содержит два простых модальных окна bootstrap. Первое содержит сообщение об успешной отправки и автоматически выводится при отправке, второе содержит саму форму обратной связи (код формы идентичен форме из представления contact (app/views/site/contacts.php)).
Далее в основном макете (app/views/layouts/main.php) добавляем инициализацию виджета и ссылку (или кнопку) для вызова всплывающего (модального) окна с формой обратной связи.
Добавляем в use виджет с формой обратной связи:
use app\components\FBFWidget;
Добавляем (меняем) ссылку для вывода всплывающего окна с формой обратной связи в меню (Nav::widget):
['label' => 'Contact', 'url' => '#', 'options' => ['data-toggle' => 'modal', 'data-target' => '#myModal']],
Вызываем виджет со всплывающим (модальным) окном, которое содержит форму обратной связи:
<?= FBFWidget::widget([]) ?>
В итоге файл app/views/layouts/main.php будет выглядеть следующим образом (изменения в строках: 7, 38, 71):
<?php
use yii\helpers\Html;
use yii\bootstrap\Nav;
use yii\bootstrap\NavBar;
use yii\widgets\Breadcrumbs;
use app\assets\AppAsset;
use app\components\FBFWidget;
AppAsset::register($this);
?>
<?php $this->beginPage() ?>
<!DOCTYPE html>
<html lang="<?= Yii::$app->language ?>">
<head>
<meta charset="<?= Yii::$app->charset ?>">
<meta name="viewport" content="width=device-width, initial-scale=1">
<?= Html::csrfMetaTags() ?>
<title><?= Html::encode($this->title) ?></title>
<?php $this->head() ?>
</head>
<body>
<?php $this->beginBody() ?>
<div class="wrap">
<?php
NavBar::begin([
'brandLabel' => 'My Company',
'brandUrl' => Yii::$app->homeUrl,
'options' => [
'class' => 'navbar-inverse navbar-fixed-top',
],
]);
echo Nav::widget([
'options' => ['class' => 'navbar-nav navbar-right'],
'items' => [
['label' => 'Home', 'url' => ['/site/index']],
['label' => 'About', 'url' => ['/site/about']],
['label' => 'Contact', 'url' => '#', 'options' => ['data-toggle' => 'modal', 'data-target' => '#myModal']],
Yii::$app->user->isGuest ? (
['label' => 'Login', 'url' => ['/site/login']]
) : (
'<li>'
. Html::beginForm(['/site/logout'], 'post')
. Html::submitButton(
'Logout (' . Yii::$app->user->identity->username . ')',
['class' => 'btn btn-link logout']
)
. Html::endForm()
. '</li>'
)
],
]);
NavBar::end();
?>
<div class="container">
<?= Breadcrumbs::widget([
'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
]) ?>
<?= $content ?>
</div>
</div>
<footer class="footer">
<div class="container">
<p class="pull-left">© My Company <?= date('Y') ?></p>
<p class="pull-right"><?= Yii::powered() ?></p>
</div>
</footer>
<?= FBFWidget::widget([]) ?>
<?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage() ?>
Результат:
Форма обратной связи во всплывающем окне для Yii2 готова, пример с исходным кодом можно скачать с github: https://github.com/devreadwrite/yii2-fbf-in-modal.
devreadwrite.com



Подборка адаптивных шаблонов для вашей CMS
Статьи по
Как получить и установить HTTPS сертификат на сайта

Комментарии
В чём может быть проблема?
ОтветитьСделал всё по статье. При подключении use app\components\FBFWidget; Yii2 не видит сomponents и phpStorm подсвечивает его красным. Соответственно ошибка Не вижу представление. Может его ещё где то нужно прописать ?
Шаблон basic? Если advanced то пути будут примерно такие use frontend\components
ОтветитьВиджеты не нужно прописывать в конфиге. Их нужно просто подключить на той странице, на который Вы их вызываете. В конфиге подключаются компоненты, модули, но не виджеты
ОтветитьСделал все как сказано, а окно не открывается. Хоть код подгружается. В чем может быть проблема?
ОтветитьСкорее всего чего-то не хватает в js bootstrap. Для начала можно проверить работу модальных окон стандартным кодом из примера bootstrap (https://getbootstrap.com/javascript/#modals):
Если модальное окно не открывается, то разобраться почему. Если открывается, то возможно id всплывающего окна из примера уже где-то встречается по коду и его нужно заменить.Ответить
Отличный урок 2 часа возни и все работает, большой респект автору я бы поучился у вас на создание приложений на yii2
ОтветитьДля полноты картины осталось добавить авторизацию/регистрацию/восстановление пароля во всплывающем окне
ОтветитьПредлагаю улучшение. Добавить отправку данных через AJAX и сменить капчу на reCAPTCHA (Добавляем reCAPTCHA от Google на сайт). Будет вообще гуд.
ОтветитьПоддерживаю, плюс добавить поле телефон и валидацию к нему
ОтветитьТолько отправку данных AJAX или валидацию тоже?
ОтветитьСпасибо за урок, попробовал на advanced, работает и письмо отправляется. Единственное подскажите с проблемой, у меня не происходит замена содержания модального окна в случае успешной отправки, т.е. окошко просто исчезает и окна myModalSendOk не получаю, и форма не сбрасывается после отправки.
ОтветитьПроверьте работает ли:
$('#myModalSendOk').modal('show');Попробуйте сделать вызов в другом месте и проверьте само модальном окно.Ответить
Заменил эту строчку $('#myModalSendOk').modal('show'); на alert('ok'); и при отправке алерт всплыл, означает ли это, что должно работать?
ОтветитьДобавьте это в body:
$( document ).ready(function() {
alert('test');
$('#myModalSendOk').modal('show');
});
Показывает модальное окно?Ответить
Странно, алерт показало, а модальное окно нет
ОтветитьТогда проверьте еще раз все что связано с модальным окном, id, место вызова (может оно вызывается до инициализации bootsеrap) и т.д., как только оно будет выведено с помощью кода выше, сможете его вывести после успешной отправки ФОС
ОтветитьСпасибо за помощь, оказывается дело было в неправильном подключении bootstrap.css
Ответитьподелитесь, что сделали, столкнулся с той же проблемой :)
ОтветитьПредлагаю улучшения:
Ответить1. Виджет вынести из папки component в папку widgets где ему и место
2. В yii2 интегрирован bootstrap, так почему бы не использовать встроеный инструментрий для создания модальных окон?
Спасибо за урок! все получилось ,кроме того, что письмо на ящик не приходит ( В чем может быть проблема?
ОтветитьПосле успешной отправки формы попробовал обновить страницу...Происходит повторная отправка
Ответить<?php
Ответитьnamespace app\components;
use Yii;use yii\base\Widget;use yii\helpers\Html;use app\models\AskForm;
class AskFormWidget extends Widget { public $model; public function init() { parent::init(); }
public function run() { $model = new AskForm(); if ($model->load(Yii::$app->request->post()) && $model->validate()) { if ($model->sendAsk()) { Yii::$app->session->setFlash('successAskForm', Yii::t('app', $model->name)); //$model->unsetAttributes(); } else { Yii::$app->session->setFlash('errorAskForm', Yii::t('app', $model->name)); } Yii::$app->getResponse()->redirect( Yii::$app->request->url )->send(); Yii::$app->end(); } return $this->render('ask_form', [ 'model' => $model, ]); }}
добавьте в вид формы<?= Html::submitButton('Отправить',['class'=>'btn btn-success', 'Id'=> 'button'])?>
Ответить<div class="result">
<span id="answer"></span>
<span id="loader" style="display:none"></span>
</div>
и напишите ajax
var $form = $('#contact-form');
button = $('#button'),
answer = $('#answer'),
loader = $('#loader');
$form.on('beforeSubmit', function() {
var data = $form.serialize();
$.ajax({
url: $form.attr('action'),
type: 'POST',
data: data,
success: function (data) {
loader.fadeOut(300, function() {
answer.text('форма отправлина');
});
},
error: function(jqXHR, errMsg) {
alert(errMsg);
},
complete: function(){
$('#button').attr("disabled", true);
},
});
return false;
});
Доброе утро.
ОтветитьСкажите, а как сделать такой же виджет, но с возможностью редактировать данные?
Я пытаюсь сделать виджет подачи объявления.
С первой частью проблем нет. Создал виджет, подключил вид формы, создал пустой экземпляр модели.
Форма работает, объявление записывается в базу.
А вот с редактированием проблема.
Никак не могу понять, как при клике по ссылке "редактировать" передать заполненный экземпляр модели в модальное окно?
Как вариант можно сделать еще одну форму (или использовать туже). При нажатии на редактирование js должен делать ajax запрос на получения данных по id и заполнять форму. Только не забудте кнопку сохранить поправить таким образом, чтобы она не добавляла новые данные, а редактировала старые.
ОтветитьПоправить это значит на нужный action отправить форму?
Хотелось бы использовать одну и туже форму.
Я переделываю форму подачи объявления, предыдущий разработчик так и сделал, получал данные по id и в success ajax запроса заполнял форму.
Но форма очень объёмная и не все данные прописал он.
Я хочу упростить этот вариант. Получить только заполненную модель и передать в вид, ну как обычно это делается.
Но опять же, у меня возникает трудность с передачей в вид.
Саму форму widget-а я расположил в frontend/widget/sale_form/views/index.php.
В ajax действии я без проблем получаю данные по id, но вот вернуть результат через renderAjax не получается.
public function actionAjaxForm(){
Вот тут и возникает проблема, выдаётся ошибка , что вид не найден. И путь, где yii ищет вид, указывает в таком видеif(Yii::$app->request->isAjax){
// получаю данные по id и пытаюсь вернуть вид формы
return renderAjax('/widget/sale_form/views/index, ['model' => $model);
}
}
Вот как вернуть в данном случае вид с заполненной моделью?
Ответить
А если так: return renderAjax('//widget/sale_form/views/index, ['model' => $model);
ОтветитьИли так: return renderAjax('@frontend/widget/sale_form/views/index, ['model' => $model);
ОтветитьС двумя слешами не пробовал, сейчас проверю, а с @frontend ошибка, что не найден вид.
ОтветитьC @frontend
с двумя слешамиОтветить
Блин, чуть мозгом не потёк)))
Такой вариант работает
return $this->renderAjax('@app/widgets/sale_form/views/index', ['model' => $model])ОтветитьИли можно как-то передать заполненную модель как параметр виджета, что-то похожее на вот это
ОтветитьSaleForm::widget('model' => $model)
Сама форма подключается в layouts/main.php