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