Yandex Metrika
sanches.free 1 просмотр

Вебформа Битрикс: своя вёрстка, Ajax через endpoint и параметры AJAX_MODE

Сначала настройте форму в админке

Для связи с лидами удобен модуль Веб‑формы. Возьмём анкету «Оставить заявку» с полями имя, телефон и комментарий.

В настройках модуля стоит отключить упрощённый режим конструктора: иначе нередко всплывают сбои почтовых шаблонов и сохранения шаблонов писем. После сохранения настройки откройте Сервисы → Веб‑формы → Настройка форм, создайте форму во вкладке «Свойства», для группы «Все пользователи» включите действие по заполнению, сохраните, затем перейдите на вкладку «Вопросы».

Создайте вопросы с символьными кодами под ваш контур (ниже условный набор полей).

  • APPLICANT_NAME — текстовое поле, обязательное, подпись «Как к вам обращаться», в ответе поле пробел в качестве подписи, тип text.
  • LINE_NUMBER — текстовое, обязательное, заголовок «Телефон», параметры ответа phone.
  • NOTICE_BODY — многострочное текстовое, необязательное, параметры можно оставить пустыми (в оригинальных инструкциях иногда ошибочно копируют phone в textarea).

Если статус результата не появился, добавьте дефолтный вроде Fresh и выдайте на все операции роль создателя результата.

Вывод через form.result.new

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

В режиме правки скопируйте пользовательский шаблон компонента в активный сайт и оставьте в каталоге единственный template.php — так проще поддерживать стили и скрипты.

Структура данных в шаблоне

Основные ключи массива $arResult:

  • isFormErrors и isFormNote равны Y при ошибках и успешном добавлении.
  • FORM_HEADER/FORM_FOOTER — открытие и закрытие тегов формы и служебные скрытые поля.
  • QUESTIONS — вопросы по символьному SID; у каждого есть CAPTION, REQUIRED, HTML_CODE, STRUCTURE.
  • arrVALUES — сохранённые значения при повторном выводе после ошибки.
  • Для капчи понадобятся isUseCaptcha, изображение и поле ввода (отдельно ниже).

Собственное оформление template.php

Логика: при успешной отправке можно показыть только текст благодарности, иначе выводится форма. Скрытое поле web_form_submit=Y сообщает модулю веб‑формы применить проверку и сохранить результат. Сообщение об ошибках имеет смысл выводить во вложении с атрибутом role="alert"; для AJAX ниже понадобится контейнер с атрибутом datawf-feedback-slot вместо жёстко пришитых классов.

<?php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) {
	die();
}
?>
<?php if ($arResult['isFormNote'] === 'Y'): ?>
	<p>Спасибо, сообщение сохранено. Менеджер свяжется с вами.</p>
<?php else: ?>
	<?=$arResult['FORM_HEADER']; ?>
	<input type="hidden" name="web_form_submit" value="Y">
	<p datawf-feedback-slot></p>
	<?php if ($arResult['isFormErrors'] === 'Y'): ?>
		<div role="alert"><?= $arResult['FORM_ERRORS_TEXT']; ?></div>
	<?php endif; ?>
	<p>
		<label><?= $arResult['QUESTIONS']['APPLICANT_NAME']['CAPTION']; ?><?= ($arResult['QUESTIONS']['APPLICANT_NAME']['REQUIRED'] === 'Y') ? '*' : ''; ?><br>
		<?= $arResult['QUESTIONS']['APPLICANT_NAME']['HTML_CODE']; ?>
		</label>
	</p>
	<p>
		<label><?= $arResult['QUESTIONS']['LINE_NUMBER']['CAPTION']; ?><?= ($arResult['QUESTIONS']['LINE_NUMBER']['REQUIRED'] === 'Y') ? '*' : ''; ?><br>
		<?= $arResult['QUESTIONS']['LINE_NUMBER']['HTML_CODE']; ?>
		</label>
	</p>
	<p>
		<label><?= $arResult['QUESTIONS']['NOTICE_BODY']['CAPTION']; ?><br>
		<?= $arResult['QUESTIONS']['NOTICE_BODY']['HTML_CODE']; ?>
		</label>
	</p>
	<p><button type="submit"><?= htmlspecialcharsbx((string)$arResult['arForm']['BUTTON']); ?></button></p>
	<?= $arResult['FORM_FOOTER']; ?>
<?php endif; ?>

Капча по необходимости

Включите капчу в настройках формы и вставьте в шаблон ветку: показ превью, подпись и поле через CAPTCHA_IMAGE и CAPTCHA_FIELD. Для замены изображения кликом подставляют свой <img> на /bitrix/tools/captcha.php с параметром captcha_sid из CAPTCHACode; глобальные параметры рисунка регулируются в модуле CAPTCHA продукта.

Ajax через отдельный endpoint

Вариант с ручным fetch или XMLHttpRequest сохраняет DOM страницы: ответ можно разобрать как JSON без полной замены блока формы модулём. Привязку оформляют после загрузки страницы, передавая адрес маленького PHP‑файла рядом с шаблоном и используя $templateFolder компонента.

function bindWebformAjax(transportForm, targetUrl, feedbackSelector) {
	if (!BX || !transportForm) {
		return;
	}
	BX.bind(transportForm, 'submit', BX.proxy(function (evt) {
		BX.PreventDefault(evt);
		var slot = transportForm.querySelector(feedbackSelector);
		if (slot) {
			slot.textContent = '';
		}
		var xhr = new XMLHttpRequest();
		xhr.open('POST', targetUrl);
		xhr.onload = function () {
			if (xhr.status !== 200) {
				alert('Ответ сервера: ' + xhr.status);
				return;
			}
			var decoded;
			try {
				decoded = JSON.parse(xhr.responseText);
			} catch (err) {
				alert('Некорректный JSON');
				return;
			}
			if (!decoded.success) {
				var lines = '';
				for (var sid in decoded.errors) {
					if (!decoded.errors.hasOwnProperty(sid)) {
						continue;
					}
					lines += decoded.errors[sid] + '\n';
				}
				if (slot) {
					slot.textContent = lines;
				}
				return;
			}
			if (slot) {
				slot.textContent = '';
			}
			if (typeof window.showLeadToast === 'function') {
				window.showLeadToast();
			}
		};
		xhr.onerror = function () {
			alert('Запрос не выполнен');
		};
		xhr.send(new FormData(transportForm));
	}, transportForm, targetUrl, feedbackSelector));
}
BX.ready(function () {
	var frm = document.getElementsByName('FORM_SID_REPLACE')[0];
	bindWebformAjax(frm, '#AJAX_ROUTE#', '[datawf-feedback-slot]');
});

В примере вместо FORM_SID_REPLACE используйте <?= htmlspecialcharsbx((string)$arResult['arForm']['SID']); ?> во встраиваемом скрипте, а маршрут #AJAX_ROUTE# замените на <?= $templateFolder ?>/ajax_handler.php в финальном template.php. Хук успеха здесь именован showLeadToast чтобы не конфликтовать с вашими утилитами.

Обработчик ajax_handler.php

Подключите проолог, модуль форм, проверьте битрикс‑сессию, отдайте JSON и запустите стандартные побочные эффекты сохранения: CRM-события, журнал результатов и почту.

<?php
require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php';

use Bitrix\Main\Loader;
use Bitrix\Main\Web\Json;

Loader::includeModule('form');

if (!check_bitrix_sessid()) {
	echo Json::encode(['success' => false, 'errors' => ['sess' => 'Сессия недействительна, перезагрузите страницу']]);
	require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/epilog_after.php';
	return;
}

$postValues = $_REQUEST;
$formIdentity = $_POST['WEB_FORM_ID'] ?? null;
$violations = CForm::Check($formIdentity, $postValues, false, 'Y', 'Y');
if (count($violations) > 0) {
	echo Json::encode(['success' => false, 'errors' => $violations]);
} elseif ($freshId = CFormResult::Add($formIdentity, $_REQUEST)) {
	if (class_exists('CFormCRM')) {
		CFormCRM::onResultAdded($formIdentity, $freshId);
	}
	CFormResult::SetEvent($freshId);
	CFormResult::Mail($freshId);
	echo Json::encode(['success' => true, 'errors' => new \stdClass()]);
} else {
	echo Json::encode(['success' => false, 'errors' => $GLOBALS['strError']]);
}

require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/epilog_after.php';
?>

Встроенный AJAX_MODE базового класса компонента

Достаточно передать параметры вида AJAX_MODE=Y, отключить скачок и историю (AJAX_OPTION_JUMP, AJAX_OPTION_HISTORY) и включить нужные побочные стили или тени. Ядро оборачивает вывод контейнером и подменяет HTML после отправки.

Минусы режима очевидны: любые обработчики ввода, навешенные один раз после DOMContentLoaded, после авто‑рендера нужно переинициализировать (маски телефона, кастомные селекты). Если разметку формы дублируют в модальном слое средствами вроде lightbox‑клонирования, Ajax заменит скрытый исходный блок, а копию покажите отдельно — либо переместите вызов компонента в общий узел модалки без «расщепления» DOM.

Свои теги вместо автоматического HTML_CODE

Когда недостаточно стандартной разметки ответов, добавьте result_modifier.php анонимной функцией, чтобы не городить дважды одно имя функции после клонирования шаблона. Функция собирает name form_{FIELD_TYPE}_{ID}, подставляет value, атрибут required и произвольные классы через поле параметров.

<?php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) {
	die();
}

$arResult['buildGuestMarkup'] = function (array $fieldMeta, array $storedValues): string {
	$firstFacet = $fieldMeta['STRUCTURE'][0];
	$answerId = (int)$firstFacet['ID'];
	$fieldKind = $firstFacet['FIELD_TYPE'];
	$inputSlot = sprintf('form_%s_%d', $fieldKind, $answerId);
	$posted = htmlspecialcharsbx((string)($storedValues[$inputSlot] ?? ''), ENT_QUOTES);
	$needsRequired = ($fieldMeta['REQUIRED'] === 'Y');
	$modifierToken = trim((string)$firstFacet['FIELD_PARAM']);
	$extraClass = $modifierToken !== '' ? ' ' . $modifierToken : '';
	$requiredChunk = $needsRequired ? ' required' : '';

	switch ($fieldKind) {
		case 'textarea':
			return '<textarea class="guest-textarea' . htmlspecialcharsbx($extraClass, ENT_QUOTES) .
				'" name="' . htmlspecialcharsbx($inputSlot, ENT_QUOTES) . '" ' . $requiredChunk . '>' .
				$posted . '</textarea>';
		default:
			return '<input class="guest-text' . htmlspecialcharsbx($extraClass, ENT_QUOTES) .
				'" type="text" name="' . htmlspecialcharsbx($inputSlot, ENT_QUOTES) .
				'" value="' . $posted . '" ' . $requiredChunk . '>';
	}
};
?>

В теле шаблона замените $arResult['QUESTIONS'][...]['HTML_CODE'] вызовом $arResult['buildGuestMarkup']($arResult['QUESTIONS'][...], $arResult['arrVALUES']) для каждого SID.

На что провериться перед боем

  • Символические коды вопросов в PHP совпадают с административными SID.
  • sessid живёт во всех отправках: либо оставляет компонент, либо передаётся из скрытых полей заголовка формы.
  • После включения AJAX_MODE перепройдите клиентские плагины ввода и убедитесь, что обработчик вешаете из обратного вызова аякс‑шаблонов или переиспользуете BX.ajax/BX.ready повторно.

Не хотите копаться сами?

Починю за 1-3 дня. Без предоплаты — оплата по результату.

15+ лет опыта с 1С-Битрикс · Без предоплаты · 7 дней гарантии