Как реализовать событие обновления динамического списка и расчет итогов?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В разработке на платформе 1С:Предприятие 8.3 динамический список является одним из самых часто используемых элементов интерфейса. Однако разработчики часто сталкиваются с существенным ограничением: у динамического списка отсутствует стандартное клиентское событие "ПриОбновлении" или "ПослеПоиска". Это создает сложности, когда необходимо вывести итоги (например, общую сумму документов), которые должны актуализироваться каждый раз, когда пользователь меняет отборы, использует поиск или просто обновляет список кнопкой "Еще — Обновить".

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

Почему нет стандартного события обновления?

Для начала проанализируем ситуацию с точки зрения архитектуры платформы. Динамический список оправдывает свое название: он считывает данные порциями (динамически) по мере прокрутки пользователем. Сервер базы данных не возвращает все 100 000 записей сразу, он отдает только те, что видны на экране. Именно поэтому расчет итогов по "видимым" данным будет методологически неверным — нам нужно знать сумму по всем записям, которые соответствуют текущим фильтрам пользователя, а не только по тем, что загружены в клиентскую часть. Отсутствие единого события связано с тем, что список может обновляться крайне часто (при каждом движении скролла или вводе символа в строку поиска), и автоматический пересчет тяжелых итогов привел бы к потере производительности.

Способ 1. Использование обработчика ожидания (Debounce)

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

Разберем реализацию с использованием метода ПодключитьОбработчикОжидания:


&НаКлиенте
Процедура ПриИзмененииОтбора(Элемент)
    // Вместо мгновенного расчета подключаем обработчик с задержкой 0.5-1 секунда
    ПодключитьОбработчикОжидания("Подключаемый_ОбновитьИтоги", 0.7, Истина);
КонецПроцедуры

&НаКлиенте
Процедура Подключаемый_ОбновитьИтоги()
    ОбновитьИтогиНаСервере();
КонецПроцедуры

Способ 2. Получение данных через исполняемую схему СКД

Начиная с версии платформы 8.3.6, у разработчиков появилась возможность программно получить схему и настройки, которые динамический список использует в данный момент. Это "золотой стандарт" для расчета итогов, так как он учитывает все пользовательские отборы, группировки и даже встроенный поиск.

Рассмотрим по шагам, как получить итог на сервере:

  1. Получаем исполняемую схему компоновки данных (СКД).
  2. Получаем текущие настройки (отборы, поиск, порядок).
  3. Выполняем компоновку и выводим результат.

&НаСервере
Функция ОбновитьИтогиНаСервере()
    // 1. Получаем схему и настройки динамического списка
    Схема = Элементы.Список.ПолучитьИсполняемуюСхемуКомпоновкиДанных();
    Настройки = Элементы.Список.ПолучитьИсполняемыеНастройкиКомпоновкиДанных();

    // 2. Подготавливаем макет компоновки
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки, , , 
        Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));

    // 3. Выполняем запрос
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);

    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
    ТаблицаРезультата = ПроцессорВывода.Вывести(ПроцессорКомпоновки);

    // 4. Получаем итог по нужной колонке
    СуммаИтог = ТаблицаРезультата.Итог("СуммаДокумента");
    Возврат СуммаИтог;
КонецФункции

Способ 3. Оптимизация через модификацию схемы

Предыдущий пример имеет один недостаток: если в списке 50 000 строк, система попытается выгрузить их все в ТаблицаЗначений на сервере, чтобы просто посчитать сумму. Это неэффективно. Проанализируем, как можно ускорить процесс, заставив СУБД выполнить агрегатный запрос SUM().

Для этого перед выполнением компоновки мы можем программно изменить схему, удалив из неё все выбранные поля и добавив только одно поле-итог. Выясним, как это реализовать:


// Внутри серверной функции перед выполнением компоновщика макета:
Схема.ВыбранныеПоля.Очистить();
НовоеПоле = Схема.ВыбранныеПоля.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
НовоеПоле.Поле = Новый ПолеКомпоновкиДанных("СуммаДокумента");
// В настройках также оставляем только агрегатную функцию, если это возможно в вашей версии

Важный момент: использование ПолучитьИсполняемыеНастройкиКомпоновкиДанных гарантирует, что даже если пользователь воспользовался сложным поиском через Alt+F, эти условия попадут в ваш запрос и итог будет корректным.

Способ 4. Использование события ПриПолученииДанныхНаСервере

Некоторые разработчики используют событие ПриПолученииДанныхНаСервере. Посмотрим на этот метод критически. Это событие срабатывает при каждой отрисовке строк списка. Если мы будем выполнять тяжелый запрос итогов прямо здесь, интерфейс начнет "тормозить" при скроллинге.

Однако, этот метод можно использовать для установки флага необходимости обновления. Выясним логику: в событии СписокПриПолученииДанныхНаСервере мы понимаем, что данные изменились. Мы можем передать этот флаг на клиент, и уже на клиенте в обработчике ПриАктивизацииСтроки (который срабатывает реже) или через короткий обработчик ожидания выполнить расчет.

Подведем итоги

Для реализации качественного интерфейса с итогами в динамическом списке рекомендуется комбинированный подход:

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

← На главную