AJAX в компонентах Битрикс: правильный способ без костылей

Многие разработчики делают AJAX в Битрикс через отдельные PHP-файлы или через роутинг ядра. Это работает, но есть правильный встроенный способ — через параметр ajaxMode и компонентный AJAX.

Способ 1: Стандартный ajaxMode

Простейший способ — передать параметр AJAX_MODE компоненту. Компонент перерисует только себя без перезагрузки страницы:

// В шаблоне страницы
$APPLICATION->IncludeComponent(
    'company:catalog.list',
    '',
    [
        'AJAX_MODE'      => 'Y',
        'AJAX_OPTION_JUMP'   => 'N',
        'AJAX_OPTION_STYLE'  => 'Y',
        'AJAX_OPTION_HISTORY'=> 'N',
    ]
);

При клике на пагинацию или фильтр страница обновит только блок компонента.

Способ 2: Ручной AJAX через action

Для сложных сценариев — собственный AJAX-обработчик прямо в компоненте:

// component.php
if ($this->request->isAjaxRequest()) {
    $action = $this->request->get('action');

    if ($action === 'load_more') {
        $page = (int) $this->request->get('page');
        $items = $this->loadItems($page);

        $this->sendResponse([
            'items' => $items,
            'hasMore' => count($items) === $this->arParams['PAGE_SIZE'],
        ]);
    }
}

// Вспомогательный метод
protected function sendResponse(array $data): void
{
    header('Content-Type: application/json; charset=utf-8');
    echo \Bitrix\Main\Web\Json::encode($data);
    die();
}

JavaScript для отправки AJAX

// Правильный способ с CSRF-токеном Битрикс
async function loadMore(page) {
    const response = await fetch(window.location.href, {
        method: 'POST',
        headers: {
            'X-Bitrix-Csrf-Token': BX.message('bitrix_sessid'),
            'Content-Type': 'application/x-www-form-urlencoded',
        },
        body: new URLSearchParams({
            action: 'load_more',
            page: page,
            sessid: BX.message('bitrix_sessid'),
        }),
    });

    const data = await response.json();
    renderItems(data.items);
}

Способ 3: Через bitrix:ajax (BX.ajax)

BX.ajax.runComponentAction(
    'company:catalog.list',  // компонент
    'loadMore',              // метод экшена
    {
        mode: 'class',
        data: { page: 2 },
    }
).then(function(response) {
    console.log(response.data);
});

Для этого в компоненте нужен класс с методами-экшенами:

// actions/LoadMore.php
namespace Company\CatalogList\Actions;

use Bitrix\Main\Engine\Action;
use Bitrix\Main\Engine\ActionFilter;

class LoadMore extends Action
{
    public function configureActions(): array
    {
        return [
            'loadMore' => [
                '-prefilters' => [ActionFilter\Csrf::class],
            ],
        ];
    }

    public function loadMoreAction(int $page = 1): array
    {
        return ['items' => fetchItems($page)];
    }
}

Защита AJAX-запросов

Всегда проверяйте сессию Битрикс:

if (!check_bitrix_sessid()) {
    $this->sendResponse(['error' => 'Invalid session']);
}

// Или через D7
if (!\Bitrix\Main\Security\Random::validateToken($token)) {
    throw new \Bitrix\Main\SystemException('Invalid CSRF token');
}

Итог

Используйте ajaxMode для простых случаев (пагинация, фильтры). Для сложной логики — компонентный AJAX с isAjaxRequest() и JSON-ответом. Не делайте отдельные PHP-файлы для AJAX — это антипаттерн который усложняет поддержку.