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