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