Как настроить отбор в динамическом списке иерархического справочника без отображения пустых папок

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

При работе с платформой 1С:Предприятие разработчики часто сталкиваются с фундаментальной особенностью отображения иерархических динамических списков (в режиме «Дерево» или «Иерархический список»). Если наложить на такой список стандартный отбор (например, по определенным элементам или конкретной группе), платформа пытается сохранить целостность структуры. Чтобы вывести подходящий под отбор элемент, система обязана показать всю цепочку его родительских групп вплоть до корневой папки справочника. В результате пользователь видит огромное количество пустых папок, внутри которых нет доступных элементов. Это сильно перегружает интерфейс и путает конечных пользователей.

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

Почему стандартный отбор «ломает» иерархию?

Прежде чем перейти к решениям, выясним причину такого поведения платформы. Динамический список считывает данные порциями. Когда включено отображение в виде дерева, СУБД делает запросы с учетом иерархических связей. Если бы платформа скрывала родительские папки, у которых «внутри» якобы ничего нет (потому что подчиненные элементы не подошли под отбор), ей пришлось бы предварительно сканировать всю таблицу справочника на всю глубину иерархии. Для больших справочников это привело бы к колоссальному падению производительности.

Поэтому разработчики платформы заложили простое правило: родительские группы отображаются всегда, если отображаются их потомки. Но как быть, если перед нами стоит задача скрыть «лишние» ветки дерева? Рассмотрим рабочие варианты.

Способ 1. Использование свойства «РодительВерхнегоУровня»

Если перед нами стоит задача ограничить видимость справочника строго одной веткой (например, конкретному пользователю разрешено видеть только папку «Комбайны» и все её подпапки), идеальным решением будет использование встроенного свойства элемента формы.

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

Разберем по шагам, как применить это свойство в коде управляемой формы (например, в обработчике события ПриСозданииНаСервере):


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

Результат: Таблица формы полностью перестроится. Папка «Комбайны» станет корневой. Все папки, которые находятся выше неё по иерархии или на одном уровне с ней, полностью исчезнут с экрана. Пользователь даже физически не сможет подняться выше установленного уровня.

Минус метода: Этот способ отлично работает только тогда, когда нужно показать одну конкретную ветку. Если пользователю нужно вывести одновременно две независимые ветки (например, «Тракторы» и «Комбайны»), свойство РодительВерхнегоУровня использовать не получится, так как оно принимает только одно значение ссылки.

Способ 2. Двойное условное оформление (Принцип маскировки «Включить-Выключить»)

Этот изящный обходной путь активно применяется разработчиками, когда нужно вывести несколько произвольных веток дерева и скрыть все остальные пустые группы. Обычное скрытие элементов через свойство условного оформления Видимость = Ложь ломает подчиненные элементы. Но мы можем применить двухэтапную логику приоритетов условного оформления динамического списка.

Рассмотрим алгоритм настройки:

  1. Первое правило оформления (низший приоритет): Применяется ко всему динамическому списку абсолютно без условий. В параметрах оформления устанавливаем свойство Видимость = Ложь. На этом этапе мы полностью «гасим» видимость всего дерева.
  2. Второе правило оформления (высший приоритет): Накладывается по условию вхождения ссылки в иерархию разрешенных папок: Ссылка В Иерархии &МассивРазрешенныхПапок. Для этого правила мы устанавливаем параметры оформления Видимость = Истина и Отображать = Истина.

Напишем программную реализацию этого метода в модуле управляемой формы:


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

Благодаря такому подходу платформа корректно отрисует только разрешенные ветки (включая группы и их внутреннее содержимое), а все неактуальные родительские узлы останутся скрытыми, не нарушая визуальное восприятие дерева.

Способ 3. Разделение интерфейса на «Дерево групп» и «Плоский список»

Проанализируем архитектурное решение, которое является стандартом разработки в типовых конфигурациях фирмы «1С» (таких как ERP, Управление торговлей или Комплексная автоматизация). Это разделение формы на две независимые области просмотра.

Спроектируем такую форму по шагам:

  1. Левая панель формы (Дерево папок): Размещаем на форме динамический список, отображающий только структуру групп справочника. В тексте запроса или в настройках списка жестко прописываем отбор: ЭтоГруппа = Истина. Так как этот список содержит только папки, наложить на него программный фильтр (например, ограничить только доступными группами) значительно легче, и он никогда не будет содержать пустых концевых ветвей.
  2. Правая панель формы (Таблица элементов): Размещаем динамический список, отображающий элементы справочника в виде плоского списка (без иерархии).
  3. Связывание списков: В обработчике события ПриАктивизацииСтроки левой таблицы (дерева папок) динамически меняем отбор в правом списке. Мы устанавливаем отбор по родителю: показывать только элементы, у которых поле Родитель равно выделенной слева группе (или находится В Иерархии этой группы).

Посмотрим на пример реализации обработчика активизации строки для левой панели:


&НаКлиенте
Процедура ДеревоГруппПриАктивизацииСтроки(Элемент)
    
    ТекущиеДанные = Элемент.ТекущиеДанные;
    Если ТекущиеДанные <> Неопределено Тогда
        // Передаем управление на сервер для обновления отбора
        УстановитьОтборПоРодителюНаСервере(ТекущиеДанные.Ссылка);
    КонецЕсли;
    
EndПроцедуры

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

Этот паттерн полностью исключает проблему пустых папок. Пользователь видит только разрешенные ему группы в левом дереве, а при клике по ним быстро получает отфильтрованный список элементов в правой части экрана.

Способ 4. Ограничение доступа на уровне СУБД (механизм RLS)

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

В этом случае необходимо использовать встроенную систему ограничения доступа на уровне записей — RLS (Row-Level Security).

Рассмотрим, почему RLS решает проблему пустых папок:

Способ 5. Изменение режима просмотра списка

Выясним еще одну важную деталь: действительно ли пользователю критически важно видеть именно древовидную структуру справочника при работе с отбором? В большинстве практических сценариев пользователю нужно просто быстро найти элементы по определенному свойству.

Если отказаться от режима просмотра дерева в пользу плоского списка, стандартный отбор в динамическом списке отработает идеально без каких-либо доработок кода.

Проанализируем шаги настройки этого варианта:

  1. У элемента формы «Таблица», отображающего наш динамический список, находим свойство РежимПросмотра и принудительно устанавливаем значение Список (вместо значений Дерево или Иерархический список).
  2. В схеме компоновки данных или настройках динамического списка задаем безусловный отбор: ЭтоГруппа = Ложь.

В результате группы полностью исключаются из интерфейса пользователя, а стандартный отбор по любым реквизитам или условию В Иерархии отрабатывает мгновенно и выводит красивый плоский список искомых элементов.

Резюме и рекомендации

Выбор конкретного решения напрямую зависит от бизнес-требований вашей задачи:

← На главную