Правильный Ajax в 1С-Битрикс

По специфике моей работы мне частенько приходится общаться с разработчиками, в том числе разработчиками на 1С-Битрикс. При постановке задач с обновлением данных без перезагрузки страницы (Ajax) я часто слышал о существенном увеличении сроков только из-за этой особенности. После очередного такого разговора, я провел вебинар для своих разработчиков, который развеивает миф о том, что Ajax сложно интегрируется в Битрикс. По материалам того вебинара я пишу эту статью, надеюсь она поможет другим разработчикам.
 
Постановка задачи
Разрабатывать мы будем систему вывода случайной цитаты из инфоблока, с возможностью поставить лайк понравившейся цитате.
 
Подготовка
Для начала создадим новый инфоблок «Цитаты», добавим одно свойство типа число, с названием «Рейтинг» и системным именем «RATING».
 
Далее наполним инфоблок несколькими тестовыми записями.
Следующим шагом мы создадим папку «ajax/quotes» в корне сайта.
 
Все запросы можно разделить на два типа:
  1. Получение данных с сервера
  2. Обновление данных
 
Условимся, что для запросов первого типа сервер будет отдавать html.
Для запросов второго типа - Json.
Далее мы рассмотрим оба этих типа, но перед этим мы должны разместить компонент вывода случайной цитаты в шаблон сайта.
Для этого откроем на редактирование файл index.php и в нужное место добавим следующий код (обращаю внимание, что необходимо скопировать шаблон компонента news.list и назвать его - quotes):
 
$APPLICATION->IncludeComponent(
"bitrix:news.list", 
"quotes", 
Array( 
"DISPLAY_DATE" => "N", // Выводить дату элемента 
"DISPLAY_NAME" => "Y", // Выводить название элемента 
"DISPLAY_PICTURE" => "N", // Выводить изображение для анонса 
"DISPLAY_PREVIEW_TEXT" => "Y", // Выводить текст анонса 
"IBLOCK_TYPE" => "services", // Тип информационного блока (используется только для проверки) 
"IBLOCK_ID" => "IBLOCK_IDD", // Код информационного блока 
"NEWS_COUNT" => "1", // Количество новостей на странице 
"SORT_BY1" => "RAND", // Поле для первой сортировки новостей 
"SORT_ORDER1" => "DESC", // Направление для первой сортировки новостей 
"SORT_BY2" => "", // Поле для второй сортировки новостей 
"SORT_ORDER2" => "", // Направление для второй сортировки новостей 
"FILTER_NAME" => "", // Фильтр 
"FIELD_CODE" => array( // Поля 
    0 => "", 
    1 => "", 
), 
"PROPERTY_CODE" => array( // Свойства 
    0 => "RATING", 
    1 => "", ), 
"DETAIL_URL" => "/content/news/#SECTION_ID#/#ELEMENT_ID#/", // URL страницы детального просмотра (по умолчанию - из настроек инфоблока) 
"PREVIEW_TRUNCATE_LEN" => "0", // Максимальная длина анонса для вывода (только для типа текст) 
"ACTIVE_DATE_FORMAT" => "d.m.Y", // Формат показа даты 
"DISPLAY_PANEL" => "N", 
"SET_TITLE" => "N", // Устанавливать заголовок страницы 
"INCLUDE_IBLOCK_INTO_CHAIN" => "N", // Включать инфоблок в цепочку навигации 
"CACHE_TIME" => "3600", // Время кеширования (сек.) 
"CACHE_FILTER" => "N", // Кешировать при установленном фильтре 
"DISPLAY_TOP_PAGER" => "N", // Выводить над списком 
"DISPLAY_BOTTOM_PAGER" => "N", // Выводить под списком 
"PAGER_TITLE" => "Новости", // Название категорий 
"PAGER_SHOW_ALWAYS" => "N", // Выводить всегда 
"PAGER_TEMPLATE" => "", // Шаблон постраничной навигации 
"PAGER_DESC_NUMBERING" => "N", // Использовать обратную навигацию 
"PAGER_SHOW_ALL" => "N", // Показывать ссылку 
"Все" "CHECK_DATES" => "Y", // Показывать только активные на данный момент элементы 
"AJAX_MODE" => "N", // Включить режим AJAX 
"AJAX_OPTION_JUMP" => "N", // Включить прокрутку к началу компонента 
"AJAX_OPTION_STYLE" => "Y", // Включить подгрузку стилей 
"AJAX_OPTION_HISTORY" => "N", // Включить эмуляцию навигации браузера 
"CACHE_TYPE" => "N", // Тип кеширования 
"CACHE_GROUPS" => "Y", // Учитывать права доступа 
"SET_BROWSER_TITLE" => "N", // Устанавливать заголовок окна браузера 
"SET_META_KEYWORDS" => "N", // Устанавливать ключевые слова страницы 
"SET_META_DESCRIPTION" => "Y", // Устанавливать описание страницы 
"SET_STATUS_404" => "N", // Устанавливать статус 404, если не найдены элемент или раздел 
"ADD_SECTIONS_CHAIN" => "N", // Включать раздел в цепочку навигации 
"HIDE_LINK_WHEN_NO_DETAIL" => "N", // Скрывать ссылку, если нет детального описания 
"PARENT_SECTION" => "", // ID раздела 
"PARENT_SECTION_CODE" => "", // Код раздела 
"INCLUDE_SUBSECTIONS" => "Y", // Показывать элементы подразделов раздела 
"PAGER_DESC_NUMBERING_CACHE_TIME" => "36000", // Время кеширования страниц для обратной навигации ), false );?> 
Предварительно заменив IBLOCK_IDD на ID вашего инфоблока цитат.
 
Загрузка данных
Для реализации загрузки данных создаем файл index.php по адресу "ajax/quotes/rand/index.php" со следующим содержимым:
 
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
$APPLICATION->IncludeComponent("bitrix:news.list", "quotes", Array( 
"DISPLAY_DATE" => "N", // Выводить дату элемента 
"DISPLAY_NAME" => "Y", // Выводить название элемента 
"DISPLAY_PICTURE" => "N", // Выводить изображение для анонса 
"DISPLAY_PREVIEW_TEXT" => "Y", // Выводить текст анонса 
"IBLOCK_TYPE" => "services", // Тип информационного блока (используется только для проверки) 
"IBLOCK_ID" => "IBLOCK_IDD", // Код информационного блока 
"NEWS_COUNT" => "1", // Количество новостей на странице 
"SORT_BY1" => "RAND", // Поле для первой сортировки новостей 
"SORT_ORDER1" => "DESC", // Направление для первой сортировки новостей 
"SORT_BY2" => "", // Поле для второй сортировки новостей 
"SORT_ORDER2" => "", // Направление для второй сортировки новостей 
"FILTER_NAME" => "", // Фильтр 
"FIELD_CODE" => array( // Поля 
    0 => "", 
    1 => "", 
), 
"PROPERTY_CODE" => array( // Свойства 
    0 => "RATING", 
    1 => "", 
), 
"DETAIL_URL" => "/content/news/#SECTION_ID#/#ELEMENT_ID#/", // URL страницы детального просмотра (по умолчанию - из настроек инфоблока) 
"PREVIEW_TRUNCATE_LEN" => "0", // Максимальная длина анонса для вывода (только для типа текст) 
"ACTIVE_DATE_FORMAT" => "d.m.Y", // Формат показа даты 
"DISPLAY_PANEL" => "N", 
"SET_TITLE" => "N", // Устанавливать заголовок страницы 
"INCLUDE_IBLOCK_INTO_CHAIN" => "N", // Включать инфоблок в цепочку навигации 
"CACHE_TIME" => "3600", // Время кеширования (сек.) 
"CACHE_FILTER" => "N", // Кешировать при установленном фильтре 
"DISPLAY_TOP_PAGER" => "N", // Выводить над списком
"DISPLAY_BOTTOM_PAGER" => "N", // Выводить под списком 
"PAGER_TITLE" => "Новости", // Название категорий 
"PAGER_SHOW_ALWAYS" => "N", // Выводить всегда 
"PAGER_TEMPLATE" => "", // Шаблон постраничной навигации 
"PAGER_DESC_NUMBERING" => "N", // Использовать обратную навигацию 
"PAGER_SHOW_ALL" => "N", // Показывать ссылку 
"Все" "CHECK_DATES" => "Y", // Показывать только активные на данный момент элементы 
"AJAX_MODE" => "N", // Включить режим AJAX 
"AJAX_OPTION_JUMP" => "N", // Включить прокрутку к началу компонента 
"AJAX_OPTION_STYLE" => "Y", // Включить подгрузку стилей 
"AJAX_OPTION_HISTORY" => "N", // Включить эмуляцию навигации браузера 
"CACHE_TYPE" => "N", // Тип кеширования 
"CACHE_GROUPS" => "Y", // Учитывать права доступа 
"SET_BROWSER_TITLE" => "N", // Устанавливать заголовок окна браузера 
"SET_META_KEYWORDS" => "N", // Устанавливать ключевые слова страницы 
"SET_META_DESCRIPTION" => "Y", // Устанавливать описание страницы 
"SET_STATUS_404" => "N", // Устанавливать статус 404, если не найдены элемент или раздел 
"ADD_SECTIONS_CHAIN" => "N", // Включать раздел в цепочку навигации 
"HIDE_LINK_WHEN_NO_DETAIL" => "N", // Скрывать ссылку, если нет детального описания 
"PARENT_SECTION" => "", // ID раздела 
"PARENT_SECTION_CODE" => "", // Код раздела 
"INCLUDE_SUBSECTIONS" => "Y", // Показывать элементы подразделов раздела 
"PAGER_DESC_NUMBERING_CACHE_TIME" => "36000", // Время кеширования страниц для обратной навигации 
), false );
 
Для обработки клика, необходимо добавить следующий код в файле script.js и подключить его в шаблоне:

$(document).ready(function() {

    // Обновляем цитату
    $('#quotes-refresh-link').on('click', function (e) {

        $.ajax({
            url: "/ajax/quotes/rand/"
        }).done(function( data )
        {
            $('#quotes-box').html('').append(data);
        });

    });
});
 
Обновление данных
Для реализации «лайка» создаем файл index.php по адресу "ajax/quotes/like/index.php" со следующим содержимым:
 
 $iblockId, "ID" => $id, "ACTIVE_DATE"=>"Y", "ACTIVE"=>"Y");
    $res = CIBlockElement::GetList(Array(), $arFilter, false, false, $arSelect);
    while($ob = $res->GetNextElement())
    {
        $arFields = $ob->GetFields();
        $new = $arFields['PROPERTY_RATING_VALUE'] + 1;
        $result['value'] = $new;

        //CIBlockElement::SetPropertyValueCode($arFields['ID'], 'RATING', $new);
        CIBlockElement::SetPropertyValuesEx($arFields['ID'], $iblockId, array(
            'RATING' => $new
        ));
    }
}


header("Content-type: text/json; charset=utf-8");
echo json_encode($result);
 
Далее, для обработки лайка добавим jquery-код в наш скрипт script.js:
$(document).ready(function() {

    // Ставим лайк
    $('body').on('click', '.quotes-like-link', function (e) {

        $.post(
            "/ajax/quotes/like/",
            {
                id: $(this).data('id')
            }
        ).done(function( data )
        {
            $(e.currentTarget).parent().find('span').html(data.value);
            $(e.currentTarget).remove();
        });
    });

});
 
В идеале - следует создать компонент с этим кодом и подключить его в этом файле, но оставим это вам в качестве домашнего задания.
 
Заключение
Вот мы и рассмотрели процесс реализации ajax на CMS 1С-Битрикс. Как вы можете видеть ничего сложного. На основе этих двух примеров может быть реализована любая другая логика. 

Комментарии