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