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