О web-разработке
и даже немного больше...

Ajax форма обратной связи на bitrix

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

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

Добавление инфоблока для записи заявок

Создаем информационный блок «Заявки», и добавляем свойства для информационного блока. В моём примере путь к созданию нового инфоблока следующий:
Контент > Инфоблоки > Типы инфоблоков > Каталог > Добавить инфоблок

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

Добавление почтового события и шаблона

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

Настройки > Настройки продукта > Почтовые события > Типы почтовых событий > Добавить тип

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

Настройки > Настройки продукта > Почтовые события > Почтовые шаблоны > Добавить шаблон

Выбираем в качестве почтового события запись с кодом NEW_USER_RESPONSE, далее, как показано на скриншоте:

После того как сохранили почтовый шаблон, можно приступать непосредственно к самой форме отправки. Сайт, который использовался в примере свёрстан с использованием bootstrap 4, этого не говорит о том, что вам необходимо его так же использовать. Вы можете реализовать эту форму самостоятельно, без использование сторонних фреймворков для верстки. В моём же примере используется модальные окна, которые хорошо описаны в документации по bootstrap 4.
Сам код формы я поместил в основной файл шаблона header.php, так как модальное окно с формой должно быть доступно по всему сайту.

<!--modal-->
<div class="modal" tabindex="-1" role="dialog" id="customer-response">
	<div class="modal-dialog" role="document">
		<div class="modal-content">
			<div class="modal-header">
				<h5 class="modal-title">Напишите нам</h5>
				<button type="button" class="close" data-dismiss="modal" aria-label="Close">
				<span aria-hidden="true">&times;</span>
				</button>
			</div>
			<div class="modal-body">
				<div class="md-resp-msg"></div>
				<form id="cust-resp-form" class="contact" name="contact" action="#" method="post">

					<input type="hidden" name="resp_item_id" id="resp_item_id" value="0">

					<div class="form-group">
						<label for="md-resp-name">Представьтесь<span class="red-text">*</span></label>
						<input type="text" id="md-resp-name" name="md-resp-name" class="form-control" placeholder="Иван Иванов" required="">
					</div>

					<div class="form-group">
						<label for="md-resp-phone">Телефон<span class="red-text">*</span></label>
						<input type="text" id="md-resp-phone" name="md-resp-phone" class="form-control" placeholder="+7(___)___-__-__" required="">
					</div>
					
					<div class="form-group">
						<label for="md-resp-email">Почта</label>
						<input type="text" id="md-resp-email" name="md-resp-email" class="form-control" placeholder="example@mail.ru">
					</div>

					<div class="form-group">
						<label for="md-resp-message">Описание заявки</label><br>
						<textarea name="md-resp-message" class="form-control" rows="5" id="md-resp-message"></textarea>
					</div>
					
					<div class="form-group">
						<p class="required-fields">* Обязательные поля для заполнения</p>
						<p class="user-agrement">Нажимая кнопку, я принимаю <a href="#">соглашение о конфиденциальности</a> и соглашаюсь с обработкой персональных данных</p>
					</div>
					
				</form>
				
			</div>
			<div class="modal-footer">
				<button type="button" class="md-resp-send">Отправить</button>
			</div>
		</div>
	</div>
</div>

Кнопка вызова модального окна так же располагается на странице, выглядит она таким образом:

<a href="javascript:void(0);" class="top-nav_callback" data-toggle="modal" data-target="#customer-response">Заказать обратный звонок</a>

Итак, действие с открыванием и закрыванием модального окна выполняется самим фреймворком bootstrap, и большого интереса для нашего поста это не представляет. Для нас интересна сама отправка данных с формы. Начинать проверку полей и отправку мы будем при нажатии на кнопке «отправить».
Код написан на js + jquery, выполняет валидацию заполнения полей, а также отправку данных на сервер:

// ----------- callback response ---------------

$(".md-resp-send").on("click",function(e){
	e.preventDefault();
	
	$(".md-resp-msg").hide();
	$(".md-resp-msg").html('');
	
	var err=0;

	// person name
	if ( $("#md-resp-name").val() == '' ){
		err++
		$("#md-resp-name").addClass("hasError");
	} else {
		$("#md-resp-name").removeClass("hasError");
	}
	
	// phone
	if ( $("#md-resp-phone").val() == '' ){
		err++
		$("#md-resp-phone").addClass("hasError");
	} else {
		$("#md-resp-phone").removeClass("hasError");
	}

	// email
	if ( $("#md-resp-email").val() != '' ){
		var pattern = /\S+@\S+\.\S+/;
		if ( !pattern.test( $("#md-resp-email").val() )){
			err++
			$("#md-resp-email").addClass("hasError");
		} else {
			$("#md-resp-email").removeClass("hasError");
		}
	} else {
		$("#md-resp-email").removeClass("hasError");
	}

	var resp_type = '';
	if ( $("#resp_item_id").val() == 0 ){
		resp_type = '?action=call';
	}

	if (err == 0){
		
		$.ajax({
			type: "POST",
			url: '/ajax.customer-response.php'+resp_type,
			data: {
				'item_id': $("#resp_item_id").val(), // set in catalog.js
				'name': $("#md-resp-name").val(),
				'phone': $("#md-resp-phone").val(),
				'email': $("#md-resp-email").val(),
				'message': $("#md-resp-message").val()
			},
			dataType: "json",
			success: function(data){

				if (data.status == true){
					$("#md-resp-name").val('');
					$("#md-resp-phone").val('');
					$("#md-resp-email").val('');
					$("#md-resp-message").val('');
				}
				
				if (data.msg && data.msg.length > 0){
					$(".md-resp-msg").fadeIn();
					$.each( data.msg, function( key,field ) {
						if (field.type == true){
							$(".md-resp-msg").append('<p class="md-true">'+field.text+'</p>');
						} else {
							$(".md-resp-msg").append('<p class="md-error">'+field.text+'</p>');
						}
					});
				}

			}
		});
	}

});

Хотелось бы немного пояснить по коду js. В коде объявляется переменная err, которая по сути является счётчиком ошибок при валидации. Если ошибок проверки полей не возникало, то значение счётчика соответственно равно 0. Это означает что после проверки полей, будет выполняться отправка данных на сервер, посредством ajax-запроса. В случае успешной отправки, значения полей будет очищаться. Если сервер отправил сообщение об ошибке или успешной отправке, они будут записываться в блок с классом .md-resp-msg, с указанием дополнительного класса для типа сообщения .md-true или .md-error. Это используется для стилизации цвета текста сообщения.

В корне сайта создаем ajax.customer-response.php который будет выполнять код на стороне сервера, при ajax-запросе.

// подключаем пролог, для использования Bitrix API без подключения шаблона
require_once($_SERVER['DOCUMENT_ROOT'] . "/bitrix/modules/main/include/prolog_before.php");

// поключаем модуль инфоблоков
CModule::IncludeModule('iblock');

$arResult = array('status' => false); // переменная для результата
$err = 0; // счётчик ошибок
$PROP = array(); // данные для полей элемента инфоблока



// если передан ID элемента, то заявка отправлена со страницы карточки товара
if (isset($_POST['item_id']) && $_POST['item_id'] > 0){
	$PROP['ITEM_ID'] = (int)$_POST['item_id'];
}

// имя пользователя
if (isset($_POST['name']) && !empty($_POST['name'])){
	$PROP['PERSON_NAME'] = htmlspecialchars( $_POST['name'], ENT_QUOTES );
} else {
	$err++;
	$arResult['msg'][] = array(
						'text' =>'Вы не указали Ваше имя.',
						'type' => false
					);
}

// указываем тему отклика, в зависимости от передаваемого типа
if (isset($_POST['action']) && $_POST['action'] == 'call'){
	$TITLE = 'Новая заявка звонка с сайта: '.$PROP['PERSON_NAME'].' от '.date("d.m.Y H:i:s");
} else {
	$TITLE = 'Новая заявка: '.$PROP['PERSON_NAME'].' от '.date("d.m.Y H:i:s");
}

// номер телефона
if (isset($_POST['phone']) && !empty($_POST['phone'])){
	$PROP['PHONE'] = htmlspecialchars( $_POST['phone'], ENT_QUOTES );
} else {
	$err++;
	$arResult['msg'][] = array(
						'text' =>'Вы не указали номер телефона.',
						'type' => false
					);
}

// почтовый адрес
if (isset($_POST['email']) && filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)){
	$PROP['EMAIL'] = htmlspecialchars( $_POST['email'], ENT_QUOTES );
}

// сообщение от пользователя
if (isset($_POST['message']) && !empty($_POST['message'])){
	$PREVIEW_TEXT = htmlspecialchars( $_POST['message'], ENT_QUOTES );
}

// страница, с которой был отправлен запрос
$PROP['HTTP_REFERER'] = $_SERVER['HTTP_REFERER'];

if ($err == 0){

	$el = new CIBlockElement;
	// массив полей для нового элемента
	$arElem = Array(
				"IBLOCK_SECTION_ID" => false,
				"IBLOCK_ID"      => 9,
				"PROPERTY_VALUES"=> $PROP,
				"NAME"           => $TITLE,
				"ACTIVE"         => "Y",
				"PREVIEW_TEXT"   => $PREVIEW_TEXT
			);


	if ($PRODUCT_ID = $el->Add($arElem)){
		// устанавливаем статус
		$arResult['status'] = true;
		$arResult['msg'][] = array(
								'text' =>'Ваши данные отправлены успешно!<br>Ожидайте звонка наших операторов.',
								'type' => true
							);
	
		// подготавливаем поля для почтового события
		$arEventFields = array(
						'ITEM_ID' => $PROP['ITEM_ID'],
						'PERSON_NAME' => $PROP['PERSON_NAME'],
						'PERSON_MAIL' => $PROP['EMAIL'],
						'PERSON_PHONE' => $PROP['PHONE'],
						'HTTP_REFERER' => $PROP['HTTP_REFERER'],
						'RESPONSE_THEME' => $TITLE
					);

		// отправка почты
		CEvent::Send("NEW_USER_RESPONSE", "s1", $arEventFields);
	
	} else {

		$arResult['msg'][] = array(
					'text' =>'Не удалось сохранить запись. ' . $el->LAST_ERROR,
					'type' => false
				);
	}

}

echo json_encode($arResult);

Код на стороне сервера довольно прост, не смотря на его объем. Первое что выполняется – проверка отправленных полей, количество ошибок записывается в переменную $err, как вы, наверное, уже поняли с примером на js, если количество ошибок равно нулю, создается элемент в инфоблоке, а после вызывается почтовое событие, которому передаются ключевые поля для почтового шаблона. В качестве результата скрипт возвращает массив полей, конвертированный в строку json. Ключевой параметр в массиве, обозначающий успешность выполнения операции называется «status», по умолчанию он равен false, при успешном выполнении параметр переводится в значение true. Параллельно с ним, так же отправляются сообщения посредством поля msg. Сообщение формируется из двух полей, text – текст сообщения, type – обозначает тип сообщения, может быть true – успех, false – ошибка. Вот в целом собственно и всё. Если остались какие-либо вопросы, вы можете писать их в комментарии. Разумеется, форму можно переделать под ваши нужды, к примеру, добавить полей, или наоборот убрать их. Всё зависит от ваших задач.

Опубликован: 16.09.2019 г.

См. также:

«Не удалось установить соединение с сервером. Проверьте …».
Получение Email-адреса покупателя в заказе (Bitrix D7)
Работа с URL-адресами в Bitrix D7
Работа с купонами в Bitrix API
Добавляем пункт меню для списков в админке Битрикс
Диалоговые окна в Bitrix API
Создание инфоблока при установке модуля
Создание копии корзины из заказа на Bitrix D7

Комментарии

  1. Михаил пишет:

    Добрый день. Расскажите как подключить гугл капчу к данной форме? Заранее благодарен.

  2. htmaker пишет:
  3. Роман пишет:

    Добрый день! Спасибо за хорошую и подробную инструкцию. Остался вопрос, как грамотно использовать 5 форм (с учетом в любом месте сайта, на одной или разных страницах) желательно не через id (например класс, конечно кроме ID самой форм), все формы с разным набором полей (где одно, а где четыре). Подскажите как правильно исправить ваш код.

  4. htmaker пишет:

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

  5. Сергей пишет:

    Добрый день!
    Скажите код в ajax.customer-response.php указывать как в примере или синтаксис в примере не полный (в частности нету в конце)
    Также у меня проблема.
    Не выводится информация о не заполненных полях при попытке отправить пустые.
    Однако, если эти поля удалить совсем в html, то при попытки отправки сообщения о незаполненных полях появляются

  6. htmaker пишет:

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

  7. Сергей пишет:

    Спасибо!
    Подскажите пожалуйста, при удалении поля Имя пользователя, и при попытке отправки, появляется ошибка:
    "Не удалось сохранить запись. Не введено название."

  8. htmaker пишет:

    В массиве добавляемого элемента $arElem нужно задать название для элемента поле NAME

  9. Роман пишет:

    Я прошу прощения за назойливость, но я не очень хорошо знаю bitrix. Не могли бы вы дать более наглядный ответ, на вопрос как отправлять разные формы с разным количеством полей. Так что бы они не выдавали ошибки на поля которых нет. Т.е. есть две формы у одной только телефон, у другой почта и телефон. Напишите пожалуйста участок кода который нужно заменить и на что что бы обе формы работали независимо с теми полями которые даны по условию выше. Буду очень сильно благодарен Вам и вашему ресурсу.

  10. htmaker пишет:

    Данная форма не совсем подходит под ваши задачи, скрипт работает с некоторыми атрибутами id элементов на форме (как вы знаете id в структуре страницы не должен повторяться), поэтому нужно переделывать разметку, переделывать js-обработчик, и проверку на стороне сервера.

  11. Сергей пишет:

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

  12. htmaker пишет:

    Стоит проверить создаётся ли запись в базе, таблица b_events, там же есть колонка со статусом отправки.

  13. Сергей пишет:

    Добрый день,
    Проверил, события в b-event сохраняются
    Статус отправки это я так понял колонка SUCCES_EXEC там у всех 0

  14. Сергей пишет:

    Разобрался
    Причина проблемы была в том что:

    в файле ajax.....-widget-response.php

    в самом низу где строка:
    // отправка почты
    CEvent::Send("NEW_USER_RESPONSE", "s1", $arEventFields);

    вместо : NEW_USER_RESPONSE нужно указывать название из "Тип события: NEW_PARTNER_JOIN" - указанного на этапе создания типа события.

    Огромное спасибо автору статья, форма агонь!

  15. Sergey пишет:

    Добрый день, все формы перестали работать
    в базе данных таблицы b_events
    DATE_EXEC
    NULL

    SUCCESS_EXEC
    N

    Скажите, пожалуйста, может это быть вызвано обновлениями Битрикса и каком направлении искать ошибку?
    Спасибо!

  16. htmaker пишет:

    Агенты в Bitrix выполняются по крону или на хитах?

  17. Андрей пишет:

    Подскажите, пожалуйста, , блок кода js вставляется в тот же файл ajax.customer-response.php?

  18. htmaker пишет:

    Нет, js-код должен исполняться в браузере пользователя и загружаться вместе с html-формой

  19. Александр пишет:

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

  20. htmaker пишет:

    У html-элементов значения атрибутов id на странице должны быть уникальными. Выход из ситуации - использовать CSS классы вместо id, и из JQuery обращаться к классам, а не по атрибуту id.

  21. Александр пишет:

    Добрый вечер, поменял id на class. Заработало только теперь если есть 2 формы нужно что бы обе были заполнены как сделать что бы не надо было заполнять обе, а только одну?

  22. htmaker пишет:

    Думаю можно попробовать найти общий родительский элемент для формы где была нажата кнопка отправки,

    $(this).parents(".имя_класса")
    

    после уже уже обращаться ко вложенным полям относительно текущего родительского элемента.

  23. Александр пишет:

    Помогло спасибо.

  24. Валерий пишет:

    Добрый день! Подскажите где, в каком файле и как вставить код отслеживания цели в Метрике вида: ym(XXXXXX,'reachGoal','target')
    Спасибо!

  25. htmaker пишет:

    Добрый день, если хотите отслеживать сам факт отправки формы пользователем, то при возврате статуса ajax-запроса (success).

  26. Валерий пишет:

    Спасибо!

  27. Graf пишет:

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

  28. Graf пишет:

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

  29. htmaker пишет:

    Добрый день. Смотрите ошибки в консоли браузера, с большой вероятностью что-то не так с JS-скриптами.

  30. Антуан пишет:

    Здравствуйте!
    По какой-то причине не отрабатывает JS, то есть вообще не отрабатывается код при нажатии на кнопку отправить.

  31. htmaker пишет:

    Вероятно есть ошибки в синтаксисе JS, из-за чего перестаёт выполняться скрипт. Смотрите ошибки в консоли браузера.

Добавить комментарий для Роман Отменить ответ

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Комментарии
  • Загрузка...
Друзья сайта