Изменяйте содержимое модального окна на основе триггерной кнопки
Часто несколько модальных окон на веб-страницах имеют почти одинаковый контент с небольшими отличиями. Вы можете использовать модальные события для создания разных модальных окон на основе одного и того же модального HTML. В следующем примере показано, как изменить заголовок модального окна в соответствии со значением атрибута data-title кнопки триггера.
.modal(‘handleupdate’)
Этот метод перенастраивает положение модального слоя, чтобы противостоять рывку, возникающему из-за появления полосы прокрутки в области просмотра, в случае, если высота модального окна изменяется таким образом, что она становится выше, чем высота области просмотра, когда она открыта.
Типичным примером этого сценария является показ скрытых элементов внутри модального окна с помощью JavaScript или загрузка содержимого внутри модального окна с помощью Ajax после активации.
.modal(‘show’)
Этот метод может быть использован для открытия модального окна вручную.
.modal(options)
Этот метод активирует контент как модальный. Это также позволяет вам устанавливать параметры для модальных окон.
Код jQuery в следующем примере будет препятствовать закрытию модального окна, когда пользователь нажимает на фон, то есть на черную область наложения позади модального окна.
Следующий код jQuery предотвратит закрытие модального окна при нажатии клавиши ESC.
1. Каркас модальных окон
Как открыть окно быстро? Самое простое решение: разместить всю разметку модального окна сразу в HTML странице. Затем скрывать/показывать это окно при помощи переключения классов CSS.
Набросаем такую разметку HTML (я назвал этот скрипт «hystmodal»):
2 Скрываем окно
Сейчас наше окно всегда видно. Когда говорят о скрытии элементов, первое что приходит на ум это переключать свойство display со значения none до нашего значения flex.
Но этот подход нас не устроит, ведь свойство display не анимируется. Все переходы дочерних элементов, указанные в свойстве transition, работать не будут.
Нам поможет другое свойство visibility:hidden. Оно скроет окно визуально, хотя и зарезервирует под него место. А так как все будущие окна на странице имеют фиксированноепозиционирование – они будут полностью скрыты и не повлияют на остальную страницу.
Добавим также классы для открытого окна:
.hystmodal--active{
visibility: visible;
}
.hystmodal--active .hystmodal__window{
transform: scale(1);
opacity: 1;
}
3 Оформление подложки
В лучшем случае, нам нужен отдельный html-элемент в качестве оверлея. Можно использовать и имеющийся элемент модального окна .hystmodal в качестве оверлея, но тогда анимация на этом элементе (например переход opacity) будет затрагивать и внутренние элементы. В итоге, не получится анимировать разные свойства для окна и оверлея отдельно.
Просто разместим элемент .hystmodal__shadow прямо перед закрывающим </body>. В будущем, сделаем так, чтобы этот элемент создавался автоматически из js при инициализации библиотеки.
Его свойства:
4 Отключение прокрутки страницы
Когда модальное окна открывается, мы хотим, чтобы страница под ним не прокручивалась.Самый простой способ этого добиться — повесить overflow:hidden для body или html, когда окно открывается. Однако с этим есть проблема:
Проблема №4. В браузере Safari на iOS страница будет прокручиваться, даже если на тег html или body повешен overflow:hidden.Решается двумя способами, либо блокированием событий прокрутки (touchmove, touchend или touchsart) из js вида:
targetElement.ontouchend = (e) => {
e.preventDefault();
};
Однако при этом блокируется и прокрутка самого модального окна, а также все прокручиваемые блоки внутри окна, если они будут. Требуется дополнительные проверки селекторов из js, что приводит к усложнению кода, поэтому рассмотрим другой вариант.
ps: можно конечно применить библиотеку scroll-lock, в которую заложено это решение, но в статье было решено воспользоваться другим вариантом.
Другое решение – основано частично на CSS. Пусть когда окно открывается, на элемент <html> будет добавляться класс .hystmodal__opened:
.hystmodal__opened {
position: fixed;
right: 0;
left: 0;
overflow: hidden;
}
Благодаря position:fixed, окно не будет прокручиваться даже в safari, однако здесь тоже не всё гладко:
Проблема №5. При открытии/закрытии окна страница прокручивается в начало.Действительно, это происходит из-за изменения свойства position, текущая прокрутка окна сбрасывается.
Для решения, нам нужно написать следующий JS (упрощенно):
При открытии:
// Находим тег html и сохраняем его
let html = document.documentElement;
//сохраним текущую прокрутку:
let scrollPosition = window.pageYOffset;
//установим свойство top у html равное прокрутке
html.style.top = -scrollPosition "px";
html.classList.add("hystmodal__opened");
При закрытии:
html.classList.remove("hystmodal__opened");
//прокручиваем окно туда где оно было
window.scrollTo(0, scrollPosition);
html.style.top = "";
Отлично, приступим к JavaScript коду.
2 Закрытие окна по клику на оверлей
Нам нужно обработать ещё одно событие – закрытие окна по клику на элемент подложки .hystmodal__wrap. Мы можем повесить обработчик клика на документ для делегирования события как при открытии и проверить что событие произошло на .hystmodal__wrap примерно так:
document.addEventListener("click", function (e) {
const wrap = e.target.classList.contains('hystmodal__wrap');
if(!wrap) return;
e.preventDefault();
this.close();
}.bind(this));
Это будет работать, но есть один малозаметный недостаток.
Проблема №8. Если кнопку мыши нажать внутри окна, а отпустить за его пределами (над подложкой), окно закрывается.
Представьте, что в окне форма. Вы выделяете текст в поле ввода и случайно двигаете мышь чуть дальше, курсор заходит на подложку и вдруг окно закрывается, всё вдруг пропадает из виду. Не хотелось бы, чтобы так было.
Окно закрывается потому что по спецификации, если нажатие и отпускание мыши были на разных элементах, то событие click сработает на самом ближайшем общем для них элементе, а у нас это как раз .hystmodal__wrap.
Мы могли бы решить это изменением html, добавляя ещё один div сразу после .hystmodal__window и размещая его визуально под окном. Но нам бы не хотелось добавлять лишний пустой div ещё сильнее усложняя разметку.
Мы можем разбить наш addEventListener на два отдельных обработчика: для событий mousedown и mouseup и будем проверять чтобы оба события происходили именно на .hystmodal__wrap. Добавим новые обработчики событий в наш метод eventsFeeler()
document.addEventListener('mousedown', function (e) {
/**
* Проверяем было ли нажатие над .hystmodal__wrap,
* и отмечаем это в свойстве this._overlayChecker
*/
if (!e.target.classList.contains('hystmodal__wrap')) return;
this._overlayChecker = true;
}.bind(this));
document.addEventListener('mouseup', function (e) {
/**
* Проверяем было ли отпускание мыши над .hystmodal__wrap,
* и если нажатие тоже было на нём, то закрываем окно
* и обнуляем this._overlayChecker в любом случае
*/
if (this._overlayChecker && e.target.classList.contains('hystmodal__wrap')) {
e.preventDefault();
!this._overlayChecker;
this.close();
return;
}
this._overlayChecker = false;
}.bind(this));
2 Каркас библиотеки
Нам нужна совместимость со старыми браузерами включая IE11 поэтому нам нужно выбрать из 2 вариантов кодинга:
Основа нашей библиотеки единственный класс HystModal. Ниже я приведу скелет кода с комментариями, а потом добавим остальной функционал.
3 Управление фокусом
У нас заготовлено два метода для управления фокусом: focusContol() для переноса фокуса внутрь окна и обратно при его закрытии, а также focusCatcher(event) для блокирования ухода фокуса из окна.
Решения для фокуса были реализованы аналогично js-библиотеке «Micromodal» (Indrashish Ghosh). А именно:
1. В служебный массив сохраним все css селекторы на которых может быть установлен фокус (свойство помещаем в init()):
//внутри метода init или конструктора
this._focusElements = [
'a[href]',
'area[href]',
'input:not([disabled]):not([type="hidden"]):not([aria-hidden])',
'select:not([disabled]):not([aria-hidden])',
'textarea:not([disabled]):not([aria-hidden])',
'button:not([disabled]):not([aria-hidden])',
'iframe',
'object',
'embed',
'[contenteditable]',
'[tabindex]:not([tabindex^="-"])'
];
2. В методе focusContol() находим первый такой селектор в окне и устанавливаем на него фокус, если окно открывается. Если же окно закрывается – то переводим фокус на this.starter:
focusContol(){
/** Метод переносит фокус с элемента открывающего окно
* в само окно, и обратно, когда окно закрывается
* см. далее в тексте.
*/
const nodes = this.openedWindow.querySelectorAll(this._focusElements);
if (this.isOpened && this.starter) {
this.starter.focus();
} else {
if (nodes.length) nodes[0].focus();
}
}
3. В методе focusCatcher() находим в окне и превращаем в массив коллекцию всех элементов на которых может быть фокус. И проверяем, если фокус должен был выйти на пределы окна, то вместо этого устанавливаем фокус снова на первый или последний элемент (ведь фокус можно переключать как по Tab так и по Shift Tab в обратную сторону).
Результирующий код метода focusCatcher:
focusCatcher(e){
/** Метод не позволяет фокусу перейти вне окна при нажатии TAB
* элементы в окне фокусируются по кругу.
*/
// Находим все элементы на которые можно сфокусироваться
const nodes = this.openedWindow.querySelectorAll(this._focusElements);
//преобразуем в массив
const nodesArray = Array.prototype.slice.call(nodes);
//если фокуса нет в окне, то вставляем фокус на первый элемент
if (!this.openedWindow.contains(document.activeElement)) {
nodesArray[0].focus();
e.preventDefault();
} else {
const focusedItemIndex = nodesArray.indexOf(document.activeElement)
if (e.shiftKey && focusedItemIndex === 0) {
//перенос фокуса на последний элемент
nodesArray[nodesArray.length - 1].focus();
e.preventDefault();
}
if (!e.shiftKey && focusedItemIndex === nodesArray.length - 1) {
//перерос фокуса на первый элемент
nodesArray[0].focus();
e.preventDefault();
}
}
}
По сути мы реализовали все необходимое для успешного создания модальных окон, осталось ещё несколько дел:
Проблема №9. В IE11 не работают методы Element.closest() и Object.assign().
Для поддержки Element.closest, воспользуемся полифилами для closest и matches от MDN.
Можно их вставить просто так, но так как у нас проект всё равно собирается webpack, то удобно воспользоваться пакетом element-closest-polyfill который просто вставляет этот код.
Для поддержки Object.assign, можно воспользоваться уже babel-плагином @babel/plugin-transform-object-assign
Ajax форма обратной связи в модальном окне
Всем привет. Засыпали вопросами о том, как реализовать форму, которая появляется в модальном окне после нажатия на кнопку, а после отправки, выводилось бы сообщение об успехе или провале.
Думаю, полно уже подобного в интернете, но раз народ просит, то решил сделать. Тем более, подобный функционал должен присутствовать почти на каждом лендинге для реализации кнопки обратного звонка. И действительно, сейчас все больше появляется результатов АБ – тестирования, которые говорят, что открытые формы работают хуже, чем те, что спрятаны в модальное окно и открываются после нажатия на кнопу.
Некоторые утверждают, что это из-за того, что у людей потихоньку “вырабатывается иммунитет” и открытая форма – это агрессивная продажа. Якобы сейчас настало то время, когда пользователь при виде открытой формы считает, что ему пытаются что-то “впарить”. Не совсем согласен с этой теорией, но зерно истины – присутствует. Может быть в некоторых видах бизнеса это и так. Ну а сейчас давайте займемся реализацией формы.
Примечание! Я не буду подробно описывать каждое действие, а предлагаю вам готовый вариант в исходнике. Если возникнут вопросы – пишите в комментариях. Будем разбираться 🙂
Сегодня начнем не с jQuery, а с верстки кнопки и формы. Все скрипты подключим в конце страницы.
Кнопка, по нажатию на которую будет открываться модальное окно:
<a class="mainButton" href="#modal">Оставить заявку</a>
Класс можете задать любой, а вот в href напишите #modal – это будет id у контейнера с затенением и контактной формой.
Теперь приведу код формы и блока, на котором будет располагаться форма:
<div class="remodal" data-remodal-id="modal" role="dialog" aria-labelledby="modal1Title" aria-describedby="modal1Desc"> <div class="remodalBorder"> <img src="img/sendico.png"> <button data-remodal-action="close" class="remodal-close" aria-label="Close"></button> <form id="form"> <h2 id="modal1Title">Оставьте ваши контактные данные и наш консультант свяжется с вами</h2> <input type="text" class="putName" name="name" placeholder="Ваше ваше имя" required> <input name="phone" type="tel" class="putPhone" placeholder="Введите номер телефона" required> <input type="submit" name="submit" class="btn" value="ОТПРАВИТЬ"> <input type="hidden" name="formData" value="Заявка с сайта"> <a style="font-size:12px; text-align:center; color:rgba(255, 255, 255, .3);" href="#">Хочу такую форму на свой сайт</a> </form> </div> </div>
Добавив стили, выглядеть это стало так:
Для создания модального окна, использовалась библиотека Remodal. Это набор из css и js файлов, как раз для создания анимированных модальных окон. Можете скачать по ссылке или уже с моими правками в конце статьи.
Между тегами head подключаем стили:
<link rel="stylesheet" href="css/remodal.css"> <link rel="stylesheet" href="css/remodal-default-theme.css">
А перед закрывающимся тегом body – добавляем скрипты:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script> <script src="dist/remodal.min.js"></script> <script src="js/script.js"></script>
Script.js – это скрипт для обработки формы. Тот самый Ajax, который позволяет нам осуществить всю процедуру без перезагрузки страницы:
$(document).ready(function () { $("form").submit(function () { // Получение ID формы var formID = $(this).attr('id'); // Добавление решётки к имени ID var formNm = $('#' formID); $.ajax({ type: "POST", url: 'mail.php', data: formNm.serialize(), success: function (data) { // Вывод текста результата отправки $(formNm).html(data); }, error: function (jqXHR, text, error) { // Вывод текста ошибки отправки $(formNm).html(error); } }); return false; }); });
Не буду приводить исходный код css и js из файлов, отвечающих за модальное окно и форму, так как они достаточно объемы. Если что, смотрите в исходнике. А вот php обработчик во многом стандартный (если можно так сказать):
<?php if ($_SERVER["REQUEST_METHOD"] == "POST") { if (isset($_POST['name'])) {$name = $_POST['name'];} if (isset($_POST['phone'])) {$phone = $_POST['phone'];} // if (isset($_POST['email'])) {$email = $_POST['email'];} if (isset($_POST['formData'])) {$formData = $_POST['formData'];} $to = "[email protected]"; /*Укажите адрес, га который должно приходить письмо*/ $sendfrom = "[email protected]"; /*Укажите адрес, с которого будет приходить письмо, можно не настоящий, нужно для формирования заголовка письма*/ $headers = "From: " . strip_tags($sendfrom) . "rn"; $headers .= "Reply-To: ". strip_tags($sendfrom) . "rn"; $headers .= "MIME-Version: 1.0rn"; $headers .= "Content-Type: text/html;charset=utf-8 rn"; $subject = "$formData"; $message = "$formData <b>Имя пославшего:</b> $name <b>Телефон:</b> $phone"; $send = mail ($to, $subject, $message, $headers); if ($send == 'true') { echo '<center> Спасибо за отправку вашего сообщения! </center>'; } else { echo '<center> <b>Ошибка. Сообщение не отправлено!</b> </center>'; } } else { http_response_code(403); echo "Попробуйте еще раз"; }?>
Пожалуйста, не забывайте менять адреса электронной почты на свои.
Вот такая ajax форма получилась. Извините, что не пытался объяснить подробно, как делался каждый элемент. Просто хотелось дать готовый результат, а описывать все анимации, появления – нет никакого смысла. Качайте исходник и внедряйте на свой сайт. А на сегодня – все. Всем удачи!
Скачать исходник
Ребята, настоятельно прошу тестировать форму на реальном или виртуальном сервере (хостинге). Убедитесь пожалуйста, что ваш сервер поддерживает php, у вас платный тариф и не тестовый период. В противном случае, в 90% случаев форма работать не будет.
Не ждите письма у себя в почтовом ящике, если вы просто открыли индексный файл в браузере и нажали кнопку “Отправить”. Php – это серверный язык!
Если вам лень разбираться и самостоятельно делать форму, то рекомендую обратить внимание на конструктор форм обратной связи.
Обновленная версия статьи находится тут
Html код
Код кнопки
Yii framework, форма обратной связи во сплывающем (модальном) окне с ajax отправкой данных
Информация! Пример написан с использованием Bootstrap стилей и скриптов. При необходимость html, css и js Вы можете заменить на свой, это не повлияет на общую логику работы примера.
В конечном результате получи такую форму обратной связи:
И так приступим.
Создадим модель для формы обратной связи в папке /protected/models/
, имя класса ContactForm
, имя файла модели ContactForm.php
, код модели (/protected/models/ContactForm.php
):
<?php class ContactForm extends CFormModel { public $name; public $email; public $subject; public $body; public $verifyCode; public function rules() { return array( array('name, email, body, verifyCode', 'required'), array('email', 'email'), array('verifyCode', 'captcha', 'on'=>'new'), ); } public function attributeLabels() { return array( 'verifyCode' => 'Капча', 'name' => 'Имя', 'email' => 'Э-почта', 'body' => 'Сообщение', ); } }
Теперь создадим виджет для всплывающего окна формы обратной связи в папке с виджетами /protected/widgets/
, имя класса FBModal
, имя файла модели FBModal.php
, код виджета (/protected/widgets/FBModal.php
):
<?php class FBModal extends CWidget { public function init() { $fBForm = new ContactForm('new'); $cs = Yii::app()->clientScript; $cs->registerScriptFile(Yii::app()->theme->baseUrl . '/js/fbModal.js', CClientScript::POS_END); //выводить новую капча при перезагрузки страницы Yii::app()->controller->createAction('captcha')->getVerifyCode(true); $this->render('webroot.themes.'.Yii::app()->theme->name.'.widgets.FBModal.fBForm', array('fBForm' => $fBForm)); } }
Создадим представление (view) для виджета FBModal
в папке /themes/themeName/widgets/FBModal/
, имя файла fBModal.php
, с кодом модального окна (/themes/themeName/widgets/FBModal/fBModal.php
):
<!-- Модальное окно формы обратной связи --> <div class="modal fade" id="fbModal" tabindex="-1" role="dialog" aria-labelledby="fbModalLabel" aria-hidden="true"> <div class="modal-dialog"> <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">Форма обратной связи</h4> </div> <?php $form = $this->beginWidget('CActiveForm', array( 'id' => 'uFBForm', 'action' => '/site/sendFBForm', 'enableAjaxValidation' => true, 'enableClientValidation' => true, 'method' => 'POST', 'clientOptions' => array( 'validateOnSubmit' => true, 'validateOnChange' => false, 'validateOnType' => false, 'afterValidate' => 'js:function(form, data, hasError) {if (!hasError) {fbModalSend();}}', 'errorCssClass' => 'has-error', ), 'errorMessageCssClass' => 'small text-danger', 'htmlOptions' => array('class' => 'contact-form', 'role' => 'form'), )); ?> <div class="modal-body"> <div class="form-group"> <?php echo $form->labelEx($fBForm, 'name'); echo $form->textField($fBForm, 'name', array( 'class' => 'form-control', 'placeholder' => 'Введите Ваше имя' )); echo $form->error($fBForm, 'name'); ?> </div> <div class="form-group"> <?php echo $form->labelEx($fBForm, 'email'); echo $form->textField($fBForm, 'email', array( 'class' => 'form-control', 'placeholder' => 'Введите E-mail', )); echo $form->error($fBForm, 'email'); ?> </div> <div class="form-group"> <?php echo $form->labelEx($fBForm, 'body'); echo $form->textArea($fBForm, 'body', array( 'rows' => 3, 'cols' => 40, 'class' => 'form-control', 'placeholder' => 'Введите текст сообщения' )); echo $form->error($fBForm, 'body'); ?> </div> <div class="text-right"> </div> <?php if (CCaptcha::checkRequirements()): ?> <div class="form-group"> <?php echo $form->labelEx($fBForm, 'verifyCode'); ?> <div class="row"> <div class="col-md-4"> <?php $this->widget('CCaptcha', array( 'buttonLabel' => '<br/>Новый код', 'id' => 'newCode' )); ?> </div> <div class="col-md-8"> <?php echo $form->textField($fBForm, 'verifyCode', array( 'class' => 'form-control', 'placeholder' => 'Введите текст указанный на картинке') ); echo $form->error($fBForm, 'verifyCode'); ?> </div> </div> </div> <?php endif; ?> </div> <div class="modal-footer"> <?php echo CHtml::htmlButton('Отмена', array( 'type' => 'reset', 'class' => 'btn btn-default', 'data-dismiss' => 'modal' )); echo CHtml::submitButton('Отправить', array( 'class' => 'btn btn-primary' )); ?> </div> <?php $this->endWidget(); ?> </div> </div> </div> <!-- Всплывающее окно с информацией об успешной отправке сообщения --> <div class="modal fade" id="fbModalOk" tabindex="-1" role="dialog" aria-labelledby="fbModalOkLabel" aria-hidden="true"> <div class="modal-dialog"> <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">Форма обратной связи</h4> </div> <div class="modal-body"> <p>Сообщение успешно отправлено.</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Закрыть</button> </div> </div> </div> </div> <!-- Всплывающее окно с информацией об ошибке при отправке сообщения (при необходимости) --> <!-- ... -->
JavaScript файл для виджета (подключается в классе виджета FBModal
, строка 9). Путь к файлу /themes/themeName/js/
, имя файла fbModal.js
. Скрипт скрывает модальное окно с формой обратной связи после успешной отправки сообщения, очищает поле с текстом сообщения и выводит окно с информацией об успешной отправке сообщения. Код (/themes/themeName/js/fbModal.js
):
function fbModalSend() { $('#fbModal').modal('hide'); $('#fbModalOk').modal('show'); $("#ContactForm_body").val(""); $("#ContactForm_verifyCode").val(""); $.ajax({ url: "/site/captcha?refresh=1", dataType: 'json', cache: false, success: function(data) { $('#yw1').attr('src', data['url']); $('body').data('captcha.hash', [data['hash1'], data['hash2']]); //обновим капчу после успешной отправки $('#newCode_button').click(); } }); }
Настройка капчи. Так как у нас в форме обратной связи используется стандартная капча фреймворка, а наш виджет может вызываться в любой части проекта (например в модуле), то внесем настройки капчи в класс предок контроллеров Controller
который находиться в папке /protected/components/
, файл Controller.php
, код (/protected/components/Controller.php
):
<?php class Controller extends CController { //... public function actions() { return array_merge(parent::actions(), array( 'captcha' => array( 'class' => 'CCaptchaAction', 'backColor' => 0xFFFFFF, 'maxLength' => 4, 'minLength' => 3, //'clickableImage' => true, //'width'=> 200, //'height'=> 50, ))); } //... }
Отправка формы обратной связи в контролере SiteController
(для отправки формы обратной связи Вы можете использовать любой удобный для Вас контроллер). Код (/protected/controllers/SiteController.php
):
<?php class SiteController extends Controller { //... public function actions() { return array_merge(parent::actions(), array( 'page' => array( 'class' => 'CViewAction', ), )); } //... public function actionSendFBForm() { if (Yii::app()->request->isAjaxRequest) { $model = new ContactForm('ajax'); if (isset($_POST['ContactForm'])) { $model->attributes = $_POST['ContactForm']; if ($model->validate()) { $message = '<p>Э-почта: ' . $model->email . '</p>' . '<p>Имя: ' . $model->name . '</p>' . '<p>Сообщение: ' . $model->body . '</p>'; // ... отправка сообщения администратору ... echo CActiveForm::validate($model); Yii::app()->end(); } else { echo CActiveForm::validate($model); } } Yii::app()->end(); } else { throw new CHttpException(404, 'Указанная запись не найдена'); } } //... }
Внимание! Обратите внимание на функцию actions
, она возвращает массив с использованием функции php array_merge
. Это сделано для того что бы не потерять настройки капчи, которые находятся в классе родителе Controller
. Если этого не сделать, то при обращении к действиям (action) контроллера SiteController
Вы получите ошибку в виде исключения с текстом: Действие CCaptchaValidator.action “captcha” задано неверно: действия не найдено в текущем контроллере. Такой способ возврата массива необходимо использовать во всех контроллерах в которых будет присутствовать форма обратной связи и которые будут вызывать метод actions
. Альтернативный способ задать параметры капчи без использования array_merge
:
<?php class SomeController extends Controller { //... public function actions() { return array( 'captcha' => array( 'class'=>'CCaptchaAction', 'backColor'=>0xFFFFFF, 'maxLength'=> 4, 'minLength'=> 3, ), 'page' => array( 'class' => 'CViewAction', ), ); } //... }
Либо не используйте стандартную капчу (или вообще не используйте капчу).
Вызов формы обратной связи:
<!-- Ссылка(кнопка) вызова модального окна с формой обратной связи --> <a href="#" data-toggle="modal" data-target="#fbModal">Обратная связь</a> <?php //Подключение виджета с формой обратной связи $this->widget('application.widgets.FBModal'); ?>
Информация! Не забудьте подключить Bootstrap стили и скрипты для работы всплывающего (модального) окна. Пример:
<?php //... $cs = Yii::app()->clientScript; $cs->registerCssFile(Yii::app()->theme->baseUrl . '/css/bootstrap.min.css'); $cs->registerCssFile(Yii::app()->theme->baseUrl . '/css/style.css'); //... $cs->registerScriptFile(Yii::app()->theme->baseUrl . '/js/ie8-responsive-file-warning.js', CClientScript::POS_END, array('media' => 'lt IE 9')); $cs->registerScriptFile(Yii::app()->theme->baseUrl . '/js/ie-emulation-modes-warning.js', CClientScript::POS_END); $cs->registerScriptFile('https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js', CClientScript::POS_END, array('media' => 'lt IE 9')); $cs->registerScriptFile('https://oss.maxcdn.com/respond/1.4.2/respond.min.js', CClientScript::POS_END, array('media' => 'lt IE 9')); $cs->registerScriptFile(Yii::app()->theme->baseUrl . '/js/bootstrap.min.js', CClientScript::POS_END); $cs->registerScriptFile(Yii::app()->theme->baseUrl . '/js/ie10-viewport-bug-workaround.js', CClientScript::POS_END); //... $cs->coreScriptPosition = CClientScript::POS_END; //...
или
<link rel="stylesheet" type="text/css" href="/themes/themeName/css/bootstrap.min.css" /> <link rel="stylesheet" type="text/css" href="/themes/themeName/css/style.css" /> <!-- ... --> <script type="text/javascript" src="/themes/themeName/js/ie8-responsive-file-warning.js" media="lt IE 9"></script> <script type="text/javascript" src="/themes/themeName/js/ie-emulation-modes-warning.js"></script> <script type="text/javascript" src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js" media="lt IE 9"></script> <script type="text/javascript" src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js" media="lt IE 9"></script> <script type="text/javascript" src="/themes/themeName/js/bootstrap.min.js"></script> <script type="text/javascript" src="/themes/themeName/js/ie10-viewport-bug-workaround.js"></script> <!-- ... -->
Все, форма обратной связи во сплывающем окне – готова. Дальнейшие доработки на Ваш вкус)
Активируйте модальные окна с помощью data-* атрибутов
Вы можете активировать модальное окно Bootstrap, нажав на кнопку или ссылку через data-* атрибуты без написания кода JavaScript. Посмотрите на следующий пример, чтобы увидеть, как это работает:
Активируйте модальные окна через javascript
Вы также можете активировать модальное окно Bootstrap через JavaScript — просто вызовите метод modal() с идентификатором окна или его селектором класса в вашем коде JavaScript.
Базовый код модального окна
Вы можете легко создавать очень умные и гибкие диалоговые окна с помощью модального плагина Bootstrap. В следующем примере представлена базовая структура для создания простого модального окна с заголовком, телом сообщения и нижним колонтитулом, содержащим кнопки действий для пользователя.
Все сделал по инструкции, но форма не работает, где искать ошибку?
В первую очередь советую заглянуть в консоль браузера и проверить наличие ошибок. Также проверьте подключена ли у вас библиотека jQuery. Проверьте правильность подключения файла scripts.js. Если все хорошо, то попробуйте включить отладку опцией debug: true. После включения смотрите консоль на наличие ошибок.
Вот такая вот форма. Используйте на своем сайте, надеюсь она будет вам полезна. Что еще сказать? Давайте теперь говорить будете вы — в комментариях. Спрашивайте, если что непонятно. Также, если найдете ошибку, то прошу сообщить незамедлительно, исправим…
На этом все. Спасибо за внимание. До встречи в следующих постах!
Загружайте контент в модальные окна через ajax
Вы также можете загрузить удаленный контент в модальном окне Bootstrap через Ajax.
Нужна система управления производством? Система управление производством автоматизирует процессы подготовки производства. Автоматизация управления производством затрагивает планирование и контроль хода производства промышленного предприятия.
В следующем примере содержимое внутри модального окна будет вставлено из удаленного файла после активации с использованием метода jQuery load() и события Bootstrap show.bs.modal.
Изменяйте размеры модальных окон
Bootstrap дает вам возможность масштабировать модальные окна. Вы можете создавать малые, большие и очень большие окна, добавив дополнительный класс .modal-sm, .modal-lg или .modal-xl соответственно в элемент с классом.modal-dialog. Пример:
Инициализация формы
Сразу отмечу, что валидация полей организовано средствами HTML5.
Форма вызывается методом .simpleSendForm(), например:
$('#idForm').simpleSendForm();
Вместо #idForm указываем индификатор формы. Вообще код инициализации формы вы можете найти в файле scripts.js. Код вызова плагина можно вырезать оттуда и прописать прямо перед </body>. Не забываем про jQuery.(document).ready().
Форма может принимать некоторые опции.
Используйте сетку bootstrap внутри модальных окон
Вы также можете использовать сетку Bootstrap в модальных окнах. Просто используйте класс .row для создания строк и классы .col- *, .col-sm- *, .col-md- *, .col-lg- * и .col-xl- * для создания столбцов внутри элемента с классом .modal. Давайте посмотрим на пример:
Как во время отправки ajax запроса сделать всплывающее на 5 сек модальное окно?
Есть типичная форма отправки сообщения, которая отправляет данные на php
страницу c помощью ajax
с которой идет перенаправление обратно, и при этом всплывает модальное окно с благодарностью.
Как сделать так, чтобы запрос сработал (возврат на страницу за это время произошел), а модальное окно при этом повисело 5 секунд и потом исчезло, а не как сейчас появляется только на мгновение.
Важно! Запрос за это время должен сработать, сделать настройку в ajax
на 5 сек не подойдет, но и setTimeout
меня в данном случае не выручает.
$('#myForm').on('submit', function(e) {
$('#box_modal').css('display', 'block');
$('#box_modal').animate({
'opacity': 1
}, 500);
$.ajax({
type: "POST",
url: $(this).attr('action'),
data: $(this).serialize(),
success: function() {
setTimeout(function() {
$('#box_modal').css('opacity', 0);
$('#box_modal').css('display', 'none');
}, 5000);
}
});
});
#box_modal {
background-color: blue;
color: red;
font-size: 18px;
width: 100px;
height: 50px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="myForm" method="post" action="mail.php">
<input type="text" value="Hello there">
<input type="submit" value="Go">
</form>
<div id="box_modal" style="display:none;">
Thank you!
</div>
Методы
Это стандартные методы загрузки модальных окон:
Не отправляется сообщение из формы, прелодер просто бегает и все. в чем проблема?
Посмотрите, правильно ли указан путь до файла обработчика в инициализации формы:
mailUrl: — путь до файла обработчика
Также проверьте корректность включения рекаптчи. То есть если отключено, то опции recaptcha в коде инициализации и $recptchaOn в файле обработчика должны быть выставлены в false или в true, если рекаптча включена.
Объяснение кода
Для активации модального окна Bootstrap через data-* атрибуты нам в основном нужны два компонента — элемент контроллера, такой как кнопка или ссылка, и сам модальный элемент.
Внешний контейнер каждого модального элемента в документе должен иметь уникальный идентификатор (в данном случае id=”myModal”), чтобы на него можно было ориентироваться через data-target (для кнопок) или href (для гиперссылок) атрибут элемента контроллера.
Параметры
Существуют определенные параметры, которые можно передать методу modal() для настройки функциональности модального режима. Опции могут быть переданы через data-* атрибуты или JavaScript.
Для настройки модальных опций с помощью data-* атрибутов просто добавьте имя опции к data-, например data-background=”static”, data-keyboard=”false” и т. д.
Data-* атрибуты обеспечивают простой способ установки параметров модальных окон, однако JavaScript является наиболее предпочтительным способом, поскольку он предотвращает повторный вызов функций.
В следующем примере мы установили для параметра background фон static, что предотвращает закрытие модального окна при щелчке за пределами модального объекта, то есть черной области наложения.
Подключаем форму к сайту
Распаковываем архив с формой. Далее скопируйте из папки dist все содержимое в папку формы (например, ajax-form) в вашем шаблоне сайта. Далее подключаем ресурсы — стили и скрипты. В папках css и js имеются две версии — сжатая и обычная. Если вы планируете в дальнейшем вносить правки в код, то лучше подключать несжатые версии.
События
Класс Bootstrap .modal включает несколько событий для подключения к модальной функциональности.
Событие | Описание |
---|---|
show.bs.modal | Событие происходит, когда вызывается метод show() , предназначенный для открытия модального окна. |
shown.bs.modal | Событие происходит, когда модальное окно становится видимым для пользователя, т.е. когда оно будет полностью отрисовано с помощью стилей CSS. |
hide.bs.modal | Событие происходит, когда вызывается метод hide(), который предназначен для скрытия модального окна. |
hidden.bs.modal | Событие происходит, когда модальное окно становится полностью невидимым для пользователя, т.е. когда будут отработаны полностью все CSS-свойства, выполняющие этот процесс. |
В следующем примере отображается сообщение с предупреждением, когда модальное окно станет полностью невидимым для пользователя.
Форма в модальном окне
Нашу форму можно показать и в модальном окне. Модалку будет выводить библиотека Magnific Popup.
Центрируйте окна вертикально
Просто добавьте класс .modal-dialog-centered к элементу с классом .modal-dialog, чтобы вертикально отцентрировать окно. Если у модального окна длинный контент, вы можете дополнительно применить класс .modal-dialog-scrollable к .modal-dialog, чтобы сделать контентную часть прокручиваемой. Пример:
Заключение и ссылки
Повторяя начало статьи, всё изложенное выше, я оформил в маленькую библиотеку hystModal под MIT-лицензией. Вышло 3 кБ кода при загрузке с gzip. Ещё написал для неё подробную документацию на русском и английском языке.
Что вошло ещё в библиотеку hystModal, чего не было в статье:
Как включить recaptcha?
Если вы хотите включить рекаптчу в форме, то вам необходимо добавить пустой блок с классом recaptcha в html-коде формы в том месте, где вы хотите ее вывести. Далее в коде вызова плагина формы передаем опцию captcha со значением true, а опцииcaptchaPublicKey передаем ваш публичный ключ recaptcha. Публичный и приватный ключи можете получить здесь.
// ===== Init captcha in the form ====
$('#idForm').simpleSendForm({
successTitle: "Ваша заявка принята!",
successText: "Наш сотрудник свяжется с Вами в самое ближайшее время.",
autoClose: true,
autoCloseDelay: 3000,
captcha: true,
captchaPublicKey: '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI'
});
Далее открываем файл обработчика формы submit.php из директории form-submit. Ищем переменную recaptchaOn (примерно 7-я строка) и выставляем ей значение true. Далее ищем переменную $secret (примерно 89-я строка) и меняем приватный ключ на свой.
В принципе все. После этих манипуляций каптча у вас должна появиться.
Обратите внимание на демо-сайте каптча работает в тестовом режиме, так как указаны тестовые ключи от Гугл.
Теперь давайте заглянем в файл обработчика (submit.php) формы и пройдемся по основным кускам кода. Обработчик работает на языке php, поэтому если хотите протестировать форму вам необходимо будет использовать локальный сервер.
Не показывается google recaptcha в форме
Проверьте переданы ли recaptcha (вызов рекаптчи) и $recaptchaOn (файл обработчика) значения — true. Также проверьте правильно ли вы указали ключи — публичный и приватный.
Заключение
Как видите модальные окна в Boostrap имеют гибкую функциональность и множество настроек, а использовать их совсем не сложно. Надеюсь эта статья поможет вам разобраться в применении всплывающих окон Bootstrap на своем сайте, и использовать их функциональность в полной мере. Удачи!