Как убрать родительскую папку в динамическом списке 1С и настроить удобный интерфейс для планшетов?

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

При разработке мобильных рабочих мест или интерфейсов для планшетов на платформе «1С:Предприятие» разработчики часто сталкиваются с аппаратными ограничениями мобильных устройств. Одно из наиболее критичных — неудобство работы с древовидными структурами. Стандартные кнопки развертывания групп (так называемые «плюсики») на экранах планшетов выглядят слишком мелко, из-за чего пользователям сложно по ним попадать пальцем. Логичным решением кажется скрыть корневую родительскую папку, чтобы сразу показать ее содержимое на верхнем уровне списка. Давайте разберем, почему стандартные механизмы отборов здесь бессильны и как решить эту задачу правильно.

Выясняем причину: Почему не работает условное оформление и простые запросы?

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

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

Решение 1. Использование свойства «РодительВерхнегоУровня» (Рекомендуемый способ)

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

Рассмотрим по шагам, как настроить это свойство программно. Лучше всего выполнять эту операцию на сервере при создании формы:


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

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

Решение 2. Перевод в плоский список с отбором по иерархии (Специально для планшетов)

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

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

  1. Установим у таблицы формы свойство Отображение в значение Список (вместо Дерево или Иерархический список).
  2. Программно наложим на динамический список отбор, который выберет все элементы внутри целевой папки, но исключит саму эту папку.

Посмотрим на пример кода, реализующий такую настройку:


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

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

Решение 3. Использование коллекции «Дерево значений» вместо динамического списка

Бывают случаи, когда логика отображения слишком сложна для стандартного динамического списка. Например, требуется программно скрывать пустые папки на определенных уровнях или динамически менять иерархию в зависимости от сложных внешних условий. В таких ситуациях мы рекомендуем отказаться от динамического списка в пользу реквизита формы с типом ДеревоЗначений.

Выясним, как это реализовать по шагам:

  1. Создадим на форме реквизит с типом ДеревоЗначений и выведем его в виде таблицы на форму.
  2. Напишем запрос, выбирающий данные из базы данных с нужной нам фильтрацией.
  3. Программно выгрузим результат запроса в дерево значений и свяжем его с интерфейсом.

Разберем пример реализации заполнения дерева значений:


&НаСервере
Процедура ЗаполнитьДеревоЗначенийНаФорме()
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	Номенклатура.Ссылка КАК Ссылка,
        |	Номенклатура.Родитель КАК Родитель,
        |	Номенклатура.ЭтоГруппа КАК ЭтоГруппа,
        |	Номенклатура.Наименование КАК Наименование
        |ИЗ
        |	Справочник.Номенклатура КАК Номенклатура
        |ГДЕ
        |	Номенклатура.Ссылка В ИЕРАРХИИ(&РодительскаяПапка)
        |	И Номенклатура.Ссылка <> &РодительскаяПапка";
        
    Запрос.УстановитьПараметр("РодительскаяПапка", Справочники.Номенклатура.НайтиПоНаименованию("НашаПапка"));
    
    РезультатЗапроса = Запрос.Выполнить();
    
    // Выгружаем данные с обходом по иерархии
    ДеревоОбъект = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);
    
    // Заполняем реквизит формы типа ДеревоЗначений
    ЗначениеВРеквизитФормы(ДеревоОбъект, "ДеревоНоменклатуры");
    
КонецПроцедуры

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

Резюме и рекомендации по выбору решения

Для выбора оптимального решения проанализируем сценарии использования нашей формы:

  1. Если вам важно сохранить динамическое обновление списка без написания сложного кода, используйте Решение 1 (свойство РодительВерхнегоУровня). Это самый надежный и быстрый способ в разработке.
  2. Если ваше приложение ориентировано исключительно на мобильные устройства и планшеты, используйте Решение 2 (плоский список с отбором). Он исключает мелкие элементы навигации и делает работу пользователя максимально комфортной.
  3. Если перед вами стоит задача реализовать сложную кастомную иерархию, которую невозможно описать стандартными запросами динамического списка, используйте Решение 3 (программное построение Дерева значений).
← На главную