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