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

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

При разработке интерфейсов на управляемых формах часто возникает задача отобразить дополнительную сводную информацию по данным динамического списка — например, количество документов в различных статусах с учетом установленных пользователем отборов и фильтров. В обычных формах для подобных задач разработчики использовали метод ПодключитьОбработчикИзмененияДанных, однако на управляемых формах этот механизм недоступен. Разберем особенности платформы 1С:Предприятие 8.3, выясним причины ограничений и рассмотрим рабочие способы решения этой задачи.

Ограничения стандартных событий динамического списка

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

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

Способ 1. Организация собственной панели быстрых отборов

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

Разберем по шагам логику реализации:

  1. Создаем реквизиты формы для каждого требуемого отбора (например, ОтборСтатус, ОтборПериод).
  2. В событии элементов формы ПриИзменении программно модифицируем отбор динамического списка.
  3. В этом же обработчике вызываем процедуру расчета и обновления итоговых показателей.

Посмотрим на пример установки отбора и последующего пересчета показателей:


&НаКлиенте
Процедура ОтборСтатусПриИзменении(Элемент)
    УстановитьЭлементОтбораСписка("Статус", ОтборСтатус, ЗначениеЗаполнено(ОтборСтатус));
    ОбновитьСводныеПоказатели();
КонецПроцедуры

&НаСервере
Процедура УстановитьЭлементОтбораСписка(ИмяПоля, ЗначениеОтбора, Использование)
    ПолеСКД = Новый ПолеКомпоновкиДанных(ИмяПоля);
    ОтборСписка = Список.КомпоновщикНастроек.ФиксированныеНастройки.Отбор;
    
    ЭлементОтбора = Неопределено;
    Для Каждого Элемент Из ОтборСписка.Элементы Цикл
        Если Элемент.ЛевоеЗначение = ПолеСКД Тогда
            ЭлементОтбора = Элемент;
            Прервать;
        КонецЕсли;
    КонецЦикла;
    
    Если ЭлементОтбора = Неопределено Тогда
        ЭлементОтбора = ОтборСписка.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
        ЭлементОтбора.ЛевоеЗначение = ПолеСКД;
        ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
    КонецЕсли;
    
    ЭлементОтбора.Использование = Использование;
    ЭлементОтбора.ПравоеЗначение = ЗначениеОтбора;
КонецПроцедуры

Способ 2. Расчет агрегатных данных через СКД списка

Когда пользователь устанавливает произвольные фильтры через стандартное меню «Настроить список» или поиск, необходимо выполнить отдельный запрос для подсчета количества записей с учетом всех наложенных условий. Для этого используем компоновщик макета, чтобы получить готовый текст запроса динамического списка со всеми примененными пользовательскими настройками.

Рассмотрим серверную процедуру получения итогов:


&НаСервере
Процедура РассчитатьКоличествоПоСтатусам()
    Схема = Элементы.Список.ПолучитьИсполняемуюСхемуКомпоновкиДанных();
    Настройки = Список.КомпоновщикНастроек.ПолучитьНастройки();
    
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки,,, Тип("ГенераторМакетаКомпоновкиДанных"));
    
    // Получаем результирующий текст запроса с внедренными отборами
    ТекстЗапросаСКД = "";
    Для Каждого НаборДанных Из МакетКомпоновки.НаборыДанных Цикл
        Если ТипЗнч(НаборДанных) = Тип("НаборДанныхЗапросМакетаКомпоновкиДанных") Тогда
            ТекстЗапросаСКД = НаборДанных.Запрос;
            Прервать;
        КонецЕсли;
    КонецЦикла;
    
    Если ПустаяСтрока(ТекстЗапросаСКД) Тогда
        Возврат;
    КонецЕсли;
    
    // Оборачиваем сформированный запрос для подсчета итогов по статусам
    ТекстИтоговогоЗапроса = 
        "ВЫБРАТЬ
        |    ВложенныйЗапрос.Статус КАК Статус,
        |    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ВложенныйЗапрос.Ссылка) КАК Количество
        |ИЗ
        |    (" + ТекстЗапросаСКД + ") КАК ВложенныйЗапрос
        |СГРУППИРОВАТЬ ПО
        |    ВложенныйЗапрос.Статус";
        
    Запрос = Новый Запрос(ТекстИтоговогоЗапроса);
    Для Каждого Параметр Из МакетКомпоновки.ЗначенияПараметров Цикл
        Запрос.УстановитьПараметр(Параметр.Имя, Параметр.Значение);
    КонецЦикла;
    
    РезультатЗапроса = Запрос.Выполнить();
    // Обработка результата и вывод данных в реквизиты формы
КонецПроцедуры

Способ 3. Отложенный вызов через разовый обработчик ожидания

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

Разберем логику работы разового таймера:

  1. При возникновении события изменения отключаем ранее назначенный обработчик ожидания, чтобы предотвратить множественные вызовы.
  2. Подключаем разовый обработчик ожидания с небольшой задержкой (например, 0.5–1 секунда) с помощью метода ПодключитьОбработчикОжидания.
  3. Если пользователь продолжает ввод, таймер перезапускается. Серверный вызов расчета произойдет только после того, как пользователь сделает паузу.

Посмотрим на пример клиентского кода:


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

&НаКлиенте
Процедура ВыполнитьПересчетИтогов()
    РассчитатьКоличествоПоСтатусам();
КонецПроцедуры

Штатные механизмы платформы для отображения итогов

В современных версиях платформы 1С:Предприятие (начиная с релиза 8.3.20) для таблиц с динамическими списками реализовано встроенное свойство ОтображениеИтогов. Если задача сводится к подсчету базовых агрегатов (количество строк, суммы по числовым колонкам), рекомендуется использовать штатный функционал платформы. Включение отображения итогов в свойствах таблицы автоматически рассчитывает показатели с учетом всех активных пользовательских настроек, отборов и поиска без написания дополнительного серверного кода.

← На главную