Контактная форма без перезагрузки страницы

Контактная форма в модальном окнеВсем — привет. Сегодня решил взяться за переработку статьи об ajax форме, которая открывалась в модальном окне. Статья достаточно популярна, но имела некоторые проблемы. Дело в том, что после отправки данных, выводилось сообщение об успешной отправке и не позволяло больше отправлять письма до перезагрузки страницы. Многие из вас спрашивали, как сделать так, чтобы сообщение не заменяло форму и позволяло повторно отправлять письма. В этой статье мы это исправим и не только.

Еще, у прошлой статьи был, наверное, недостаток в том, что сложно было подключить несколько форм, а именно, нужно было дублировать скрипт, обрабатывающий форму, что не очень красиво. В этой статье поправим и этот момент. Кроме того, форма будет работать и без модального окна.

Ах да, приведу в порядок айдишники и классы, чтобы легче понималось что и зачем. Изменю дизайн формы, так интереснее. В одной из следующих статей, возможно,  подключим к этой форме reCapthсa от Google, и настроем цель «Событие», при успешной отправке, так что готовится целый цикл статей.

Как сделать форму обратной связи в модальном окне

Давайте приступим. Так как модальное окно будет вызываться при помощи jQuery плагина Remodal, то перед закрывающимся тегом </body> подключим сам jQuery и плагин Remodal. Ниже добавим скрипт, который будет отвечать за отправку формы без перезагрузки страницы. Выглядит это следующим образом:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="modalform/libs/remodal/remodal.min.js"></script>
<script src="modalform/js/form.js"></script>

Обратите внимание на путь к файлам. Я решил поместить практически все файлы в папку modalform, чтобы легче было подключать к проекту.

Прежде чем перейти к разметке формы, подключим css файлы модального окна. Я делаю это между тегами head:

 <link rel="stylesheet" href="modalform/libs/remodal/remodal.css">
 <link rel="stylesheet" href="modalform/libs/remodal/remodal-default-theme.css">
 <link rel="stylesheet" href="modalform/css/formstyle.css">

Чтобы было интереснее:

Посмотреть пример

Итак, теперь перейдем к разметке самой формы и кнопки вызывающей ее. Начнем с кнопки.

<a class="linkButton" data-remodal-target="firstModal">Оставить заявку</a>

Тут — все просто. Обычная ссылка с произвольным классом. Data-remodal-target используется для того, чтобы вызвать модальное окно, аналогично, если бы использовался href со ссылкой на id. Но зачем нам этот мусор в адресной строке. В свою очередь модальное окно с формой выглядит следующим образом:

<div class="remodal" data-remodal-id="firstModal" data-remodal-options="hashTracking: false,closeOnConfirm: false">
  <button data-remodal-action="close" class="remodal-close"></button>
  <div class="formArea">
  
  <form id="secondForm" class="form" autocomplete="off">
  <p class="formTitle">Закажите обратный звонок и наш консультант свяжется с вами</p>
  <p class="msgs"></p>

      <fieldset class="form-fieldset ui-input __first">
        <input name="uname" type="text" id="username" required tabindex="0"/>
        <label for="username">
          <span data-text="Введите ваше имя">Введите ваше имя</span>
        </label>
      </fieldset>

      <fieldset class="form-fieldset ui-input __second">
        <input name="uphone" type="tel" id="phone" tabindex="0" required pattern="^[ 0-9]+$"/>
        <label for="phone">
          <span data-text="Введите ваш телефон">Введите ваш телефон</span>
        </label>
      </fieldset>

      <input name="formInfo" class="formInfo" type="hidden" value=""/>

      <div class="form-footer">
        <input type="submit" class="formBtn" value="Обратный звонок" />
      </div>
      <p class="formCreator"><a href="https://smartlanding.biz">smartlanding.biz</a></p>
  </form>
  </div>
</div>

Хоть кода, на первый взгляд, достаточно много, на самом деле все не так сложно. Вся форма обернута в div c классом remodal. У него есть data-remodal-id с таким же параметром как у кнопки. То есть firstForm. Именно благодаря им, при клике на кнопку открывается нужное окно, в случае, если на странице их несколько.

Data-remodal-options — один из способов задать или отключить некоторые возможности скрипта для модального окна. Подробнее можно почитать на официальном из сайте. Ссылку уже давал выше. В моем случае. Я отключил появление якоря в адресной строке и запретил закрытие окно после нажатия кнопки «отправить».

Внутри сама форма с fieldset(ами). Здесь важно обратить внимание, на параграф с классом «msgs». Именно сюда будет выводиться сообщение об успешной отправке или ошибке. Раньше сообщение выводилось прямо внутри формы, заменяя весь контент внутри.

Еще один момент. Скрытое поле c классом formInfo. Оно нужно для того, чтобы отличать заявки и понимать какую именно форму заполнил пользователь, в случае, если их несколько разных. Просто заполняем нужным текстом значение value.

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

Теперь давайте посмотрим на скрипт, который поможет нам отправить форму без перезагрузки страницы. Я назвал его form.js:

$(document).ready(function () {
    $("form").submit(function () {
        // Получение ID формы
        var formID = $(this).attr('id');
        // Добавление решётки к имени ID
        var formNm = $('#' + formID);
        var message = $(formNm).find(".msgs"); // Ищет класс .msgs в текущей форме  и записываем в переменную
        var formTitle = $(formNm).find(".formTitle"); // Ищет класс .formtitle в текущей форме и записываем в переменную
        $.ajax({
            type: "POST",
            url: 'modalform/mail.php',
            data: formNm.serialize(),
            success: function (data) {
              // Вывод сообщения об успешной отправке
              message.html(data);
              formTitle.css("display","none");
              setTimeout(function(){
                //$(formNm).css("display","block");
                $('.formTitle').css("display","block");
                $('.msgs').html('');
                $('input').not(':input[type=submit], :input[type=hidden]').val('');
              }, 3000);
            },
            error: function (jqXHR, text, error) {
                // Вывод сообщения об ошибке отправки
                message.html(error);
                formTitle.css("display","none");
                // $(formNm).css("display","none");
                setTimeout(function(){
                  //$(formNm).css("display","block");
                  $('.formTitle').css("display","block");
                  $('.msgs').html('');
                  $('input').not(':input[type=submit], :input[type=hidden]').val('');
                }, 3000);
            }
        });
        return false;
    });
    //для стилей формы
      var $input = $('.form-fieldset > input');
      $input.blur(function (e) {
        $(this).toggleClass('filled', !!$(this).val());
      });
});

Давайте немного поясню, что тут происходит. Мы вызываем функцию, когда произошло событие submit у формы (нажали на отправку). Затем получаем id формы и сохраняем в переменную formNm. Теперь, id нашей формы в ней. В прошлой статье именно сюда выводилось сообщение. И именно об этом моменте я так часто писал в комментариях. Нужно просто указать другое место для вывода. В нашем случае мы все сообщения будем выводить в заранее подготовленное место. Это тег «p» с классом «msgs».

В скрипте, говорим, что на время показа сообщения об успешной или не успешной отправке, скроем заголовок. А через 3 секунды вернем все на место и отчистим поля формы вместе с сообщением.

Файл, который отправит полученные данные — mail.php. Вот его код:

<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
  if (!empty($_POST['uname']) && (!empty($_POST['uemail']) || !empty($_POST['uphone']))){
  	if (isset($_POST['uname'])) {
  		if (!empty($_POST['uname'])){
	      $uname = strip_tags($_POST['uname']) . "<br>";
	      $unameFieldset = "<b>Имя пославшего:</b>";
	     }
    }
    if (isset($_POST['uemail'])) {
    	if (!empty($_POST['uemail'])){
	      $uemail = strip_tags($_POST['uemail']) . "<br>";
	      $uemailFieldset = "<b>Почта:</b>";
	 	}
    }
    if (isset($_POST['uphone'])) {
    	if (!empty($_POST['uphone'])){
	      $uphone = strip_tags($_POST['uphone']) . "<br>";
	      $uphoneFieldset = "<b>Телефон:</b>";
	    }
    }
    if (isset($_POST['formInfo'])) {
	    if (!empty($_POST['formInfo'])){
	      $formInfo = strip_tags($_POST['formInfo']);
	      $formInfoFieldset = "<b>Тема:</b>";
	    }
    }

    $to = "dima.d.v@yandex.ru"; /*Укажите адрес, на который должно приходить письмо*/
    $sendfrom = "smart-landing@yandex.ru"; /*Укажите адрес, с которого будет приходить письмо */
    $headers  = "From: " . strip_tags($sendfrom) . "\r\n";
    $headers .= "Reply-To: ". strip_tags($sendfrom) . "\r\n";
    $headers .= "MIME-Version: 1.0\r\n";
    $headers .= "Content-Type: text/html;charset=utf-8 \r\n";
    $headers .= "Content-Transfer-Encoding: 8bit \r\n";
    $subject = "$formInfo";
    $message = "$unameFieldset $uname
                $uemailFieldset $uemail
                $uphoneFieldset $uphone
                $formInfoFieldset $formInfo";

    $send = mail ($to, $subject, $message, $headers);
        if ($send == 'true') {
            echo '<p class="success">Спасибо за отправку вашего сообщения!</p>';
        } else {
          echo '<p class="fail"><b>Ошибка. Сообщение не отправлено!</b></p>';
        }
  } else {
  	echo '<p class="fail">Ошибка. Вы заполнили не все обязательные поля!</p>';
  }
} else {
  header ("Location: https://smartlanding.biz"); // главная страница вашего лендинга
}

В нем несколько проверок:

  • Пришли ли данные методом POST, если да, то проверяем не пустые ли основные поля, если нет, то записываем в переменные и отправляем.
  • Если данные не пришли методом POST, то выкидываем на главную (то есть пользователь, каким-то образом попал сразу на страницу mail.php), а нам это не нужно, так как может отправиться пустое письмо.

На этом первая часть закончена.

Не забывайте указывать свои почтовые ящики. Кстати, на mail.ru письма могут не приходить с вашего ip. Ну и правильно, пользователи mail.ru и IE должны страдать.

Теперь, давайте сделаем так, чтобы не приходилось заполнять параметр value у скрытого поля вручную, а он заполнялся автоматически. Это может понадобиться, когда у вас одна форма, но много кнопок на landing page, которые вызывают ее. Например, один раз вы берете контакты для бесплатной консультации, а где-нибудь ниже предлагаете услугу со скидкой. Чтобы понимать по какой именно кнопке нажали и чего ждет от вас пользователь, логично было бы в письме передавать информацию об этом. Я предлагаю кнопкам (ссылкам), по которым будет вызываться модальное окно дать title. Например, так:

<a class="linkButton" data-remodal-target="firstModal" title="Консультация">Получить консультацию</a>
<a class="linkButton" data-remodal-target="secondModal" title="Обратный звонок">Обратный звонок</a>

И написать небольшой скрипт, который при клике на на нашу кнопку(ссылку) будет подставлять в скрытое поле информацию из title:

$(".linkButton").click(function() {
    $( "input[name*='formInfo']" ).val($(this).attr( "title" ));
});

То есть мы говорим, что при клике на элемент с классом linkButton, возьми текст из его title и помести в input с name параметром formInfo, где:

  • linkButton — класс нашей кнопки;
  • formInfo — значение name скрытого поля;

Это очень удобно, когда лендинг сделан по типу интернет магазина и на нем несколько товаров. Чтобы не делать несколько форм, просто задаем title кнопке и легко узнаем, какой именно товар, тариф или услугу заказал пользователь.

Скачать исходник

Если будет вылазить ошибка «not found», первым делом проверьте путь к mail.php в файле form.js

Кстати, написал статью как связать эту форму с reCptcha от Google.

Конструктор форм

140 комментариев

  • Александр

    какой id нужно прописывать для forminfo вот в этой строке?

    Ответить
  • Александр

    какой id нужно прописывать для forminfo вот в этой строке?

    <input name="forminfo" type="text" id="?" required tabindex="0"/>
    Ответить
  • dimadv7

    Да любой!

    Ответить
  • Александр

    Попробовал так и это поле не приходит (имя, телефон, mail приходят нормально). Или в обработчике еще нужно что то добавлять?

     <input name="formInfo" type="text" id="Info" tabindex="0" />
            <label for="Info">
    Ответить
  • dimadv7

    ID вообще там не нужен, в принципе. Поле formInfo заполняется, путем нажатия на кнопку c классом linkButton, у которой прописан title c нужным нам текстом для formInfo

    Ответить
  • dimadv7

    Либо, нужно самому прописать value у поля с formInfo

    Ответить
  • Ararat06

    Добрый день!

    Отличная статья, большое спасибо! реализовал на своем сайте.

    Однако недавно перестала работать эта функция:

    Поле formInfo заполняется, путем нажатия на кнопку c классом linkButton, у которой прописан title c нужным нам текстом для formInfo

    Подскажите, куда копать???

    Ответить
  • Ararat06

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

    Ответить
  • Ararat06

    Вопрос снят, разобрался.

    Скрипт подстановки должен стоять сразу после

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
    Ответить
  • Владимир

    Добрый день! Не могу победить этот скрипт подстановки! Не работает и все((

    сама кнопка:

    Заказать

    и скрипт:

    $(«.linkButton»).click(function() {
    $( «input[name='formInfo']» ).val($(this).attr( 'title' ));
    });

    Сама форма работает отлично, а вот скрипт подстановки нет

    Ответить
  • Владимир

    сама кнопка:

    <div class="btn-box">
    <button class="button linkButton wow bounce" data-remodal-target="firstModal" type="button" title="Кнопка главной страницы">Заказать</button>
    </div>
    
    Ответить
  • Владимир

    и скрипт:
    [html]

    $(«.linkButton»).click(function() {
    $( «input[name='formInfo']» ).val($(this).attr( 'title' ));
    });

    Ответить
  • dimadv7

    Должно работать, ищите ошибку в консоли.

    Ответить
  • Александр

    Здравствуйте!
    Спасибо большое за форму, всё работает отлично! На ПК и на планшете всё шикарно, а вот когда захожу с телефона (айфон) происходит косяк.
    У меня кнопки на формы рассположены, вверх, по середине и в низу лейдинга.
    Так вот, если открыть форму внизу странички, всё шикарно, если в середине, то съезжает курсор с полей, т.е. я пишу имя, а курсор не в поле, а ниже и из-за этого нельзя нажать но другое поле, приходиться убирать клавиатуру.

    Ответить
  • dimadv7

    Здравствуйте, когда писал статью, не тестировал на ios в safari, но проблема действительно существует и мне тоже удалось обнаружить ее после того, как вы сообщили об этом. Как оказалось, проблема распространенная как минимум с 11 версии ios Вот тут описывают, что подали заявку в Apple, но она открыта еще с версии 11.0.1 и до сих пор.

    На страницы есть варианты решения, но они достаточно специфичны и не всем подойдут. Посмотрите. В любом случае спасибо, что сообщили. Сделаю пометку об этой проблеме в статье.

    Ответить
  • Юрий

    Здравствуйте! Подскажите как сделать, чтобы на почту приходило письмо, где «тема» стояла та, которую добавил её заполняющий (я добавил дополнительную колонку «тема письма»)

    Ответить
  • dimadv7

    Вот тут:

    $subject = "$formInfo";
    

    Вместо $formInfo, передать данные из вашего поля.

    Ответить
  • Федор

    Кому будет интересно куда дописать клас самозакрытия)
    1. корректируем mail.php добавив в него id в сообщении про успешную отправку.

     echo '<p class="success" id="suc_msg">...;

    2. form.js

    success: function (data) {
                  // Вывод сообщения об успешной отправке
                  message.html(data);
                  formTitle.css("display","none");
                  setTimeout(function(){
                    //$(formNm).css("display","block");
                    $('.formTitle').css("display","block");
    				
    				if ( $("#suc_msg").hasClass("success") ) {
    					$('.remodal-close').click();
    				}
                    $('.msgs').html('');
                    $('input').not(':input[type=submit], :input[type=hidden]').val('');
    				
    				
                  }, 3000); 
    Ответить
  • Tiraz

    Пожалуйста подскажите как очищать «textarea»
    Куда вписать $('textarea').val(»);
    Зараннее спасибо.

    Ответить
  • Tiraz

    Сам спросил, сам ответил.

                    
    $('input').not(':input[type=submit], :input[type=hidden]').val('');
    $('form textarea').val('');
    
    Ответить
  • Tiraz

    Пытался на основе этой формы сделать отправку вложений. Не вышло. Может автор добавит третью версию, с формой отправляющей вложения?

    Ответить
  • dimadv7

    Использовать formdata нужно, а не serialize, тогда будет возможность отправлять файлы

    Ответить
  • Михаил

    Добрый день! Можете подсказать, у меня не приходят на почту письма в которых содержится +, ( ) — это я имею в виду, когда пользователь вводит в после «Телефон». Пишет: успешно отправлено, а письмо вообще не приходит.
    А, когда просто цифры, все нормально. Проверку в html убирал: [required pattern]

    Буду благодарен за ответ

    Ответить
  • dimadv7

    Первый раз с таким сталкиваюсь и слышу об этом. Какая разница, что в поле, если прошел все проверки и письмо отправлено? Я не знаю чем помочь, дело должно быть не в этом, потому что абсурд какой-то.

    Ответить
  • Михаил

    Я вас понял, большое спасибо за ответ. Попробую другой почтовый ящик использовать

    И можете, пожалуйста, еще в одном вопросе помочь: хочу сделать, чтобы после нажатия кнопки «Отправить» пользователя перебрасывало на страницу с благодарностями. Можно как то реализовать это? Буду благодарен за ответ.

    Ответить
  • dimadv7

    Это же статья о контактной форме без перезагрузки страницы. Со страницами благодарности другой подход. Есть соответствующие на блоге:
    Вот: https://smartlanding.biz/kontaktnaya-forma-s-chekboksami.html
    Вот: https://smartlanding.biz/sozdanie-formy-obratnoj-svyazi.html

    Ответить
  • Михаил

    Большое спасибо за ответ, посмотрю

    Ответить
  • Павел

    Здравствуйте, я использую SSL сертификат на сервере и видимо связи с этим скрипт просто не исполняется? загрузил ваш php файл на хостинг и открыл его http:// — скрипт заработал. Есть идеи?

    Ответить
  • dimadv7

    Здравствуйте. Я не понял вас, вы загрузили скрипт на сайт, где не установлен ssl сертификат и скрипт работает, а когда загружаете на сайт с ssl сертификатом, то скрипт не работает?

    Ответить
  • Евгений

    А как сделать, чтобы окно само закрывалось через некоторое время после отправки заявки.

    Ответить
  • Вилен

    Здравтсвуйте, у меня получатся походу конфликт со стилями самого шаблона!
    Еслии закоментирую стили шаблона, все работает норм, если открою — просто капец не правильно отображается форма. Как быть??

    Ответить
  • dimadv7

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

    Ответить
  • Егор

    Добрый день! Такая ситуация, нам одной странице две формы с разными обработчиками php. В файле form.js добавил функцию с новым id
    ( $(document).ready(function () {
    $(«#serv»).submit(function () { …)
    и прописал путь к другому php. А обработка происходит на mail.php
    Подскажи пожалуйста
    1) Как определяется форма в обработчике js
    2) Как сделать что бы обработка проходила на разных php

    Ответить
  • dimadv7

    Добрый день, вот тут:

    $("form").submit(function () {
    

    вместо $(«form») указываете id или класс формы, которую нужно обработать, и должно работать.

    Ответить
  • Егор

    поменял, заработало. появилось другое приходят сообщения с двух обработчиков mail.php и mail2.php

    Ответить
  • dimadv7

    Если привязывались к id формы и он разный у 2 форм, то должен только 1 срабатывать.

    Ответить
  • Данид

    не работает ваша отправка сообщений на gmail и прочее

    Ответить
  • Коля

    Данид, у всех работает, у тебя — нет. Делай вывод!

    Ответить
  • Александр

    Уважаемый Дмитрий (dimadv7). Спасибо Вам за труд и за то, что делитесь опытом. Попытался на базе Вашей формы сделать отправку файлов. В форму добавил поле

    	  <fieldset class="form-fieldset ui-input __third">
    	    <label for="file">
              <span  data-text="Выберите файл:">Выберите файл:</span>
            </label>
          <input name="file" type="file" id="userFile" tabindex="0" />
          </fieldset>

    В тэг добавил enctype=»multipart/form-data» В файл mail.php добавил

    $filepath = $_FILES["file"]["tmp_name"];
            $filename = $_FILES["file"]["name"];

    и т.д. В form.js меняю serialize() на FormData()

                url: "modalform/mail.php",
                data: formNm.FormData(),

    В итоге, ничего не отправляется. Добавляю в тэг action с указанием обработчика

    <form action="modalform/mail.php" id="firstForm" class="form"  method="post" autocomplete="off" enctype="multipart/form-data">

    и тогда файл и сообщение отправляются. Все ОК! Только сообщение об успешной отправке выводится в открывшемся окне mail.php, на который указал action , а не в окне remodal, как хотелось бы! Пробовал явно ставить класс formfile и id= firstForm

     $("#firstForm").submit(function ()... или  $("#formfile").submit(function ()...

    , чтобы избежать action — не работает. Подскажите, пожалуйста как решить эту проблему(вывода сообщения в модальное окно) или подскажите, что я делаю не так.

    Ответить
  • dimadv7

    Здравствуйте. Все вы правильно делаете, скорее всего ошибка где-то в обработке результата, который вам formdata возвращает:
    Вот пример функции, которую я использовал в SmartLid

           sendMail: function (formid) {
                var formId = "#" + formid;
                var fd = new FormData(document.querySelector(formId));
                $.ajax({
                    url: "./smartlid/php/smartlid.php",
                    type: "POST",
                    data: fd,
                    processData: false,
                    contentType: false,
                    beforeSend: function () {
    
                        $(formId).find('.smartlid__preloader').css('display', 'block');
                        $(formId).find('.smartlid__default-msgs').css('display', 'none');
                        $(formId).find('.smartlid__form-button').prop('disabled', true);
                        $(formId).find('.smartlid__respond-msgs').html('Отправка письма');
                    },
                    success: function (data) {
                        $(formId).find('.smartlid__preloader').css('display', 'none');
                        switch (data) {
                            case 'attantion':
                                $(formId).find('.smartlid__respond-msgs').html('').append(defaults.attantion);
                                break;
                            case 'successmsgs':
                                $(formId).find('.smartlid__respond-msgs').html('').append(defaults.successmsgs);
                                break;
                            case 'failmsgs':
                                $(formId).find('.smartlid__respond-msgs').html('').append(defaults.failmsgs);
                                break;
                            case 'failfile':
                                $(formId).find('.smartlid__respond-msgs').html('').append(defaults.failfile);
                                break;
                        }
    
                        setTimeout(() => {
                            $(formId).find('.smartlid__default-msgs').css('display', 'block');
                            $(formId).find('.smartlid__respond-msgs').html('');
                            $(formId).find('.smartlid__form-button').prop("disabled", false);
    
                        }, 4000);
    
                    },
                    complete: function (data) {
                        if (data.responseText == 'successmsgs') {
                            $(formId).find($('input').not(':input[type=hidden]')).val('');
                            $(formId).find($('textarea').val(''));
                        }
                        defaults.counter();
                    },
    
                });
            },
    

    Попробуйте по аналогии сделать и обратите внимание на:

    var fd = new FormData(document.querySelector(formId));
                $.ajax({
                    url: "./smartlid/php/smartlid.php",
                    type: "POST",
                    data: fd,
                    processData: false,
                    contentType: false,
    
    Ответить

Добавить комментарий

Подписывайтесь на обновления, чтобы ничего не пропустить.