Почему при программном создании группы справочника в 1С создается элемент и как это исправить

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

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

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

Анализ проблемы: почему ломается стандартная логика

Давайте подробно рассмотрим исходный код, который часто пишут начинающие разработчики (и который приводит к ошибке):


&НаКлиенте
Процедура СоздатьГруппу(Команда)
    
    Форма = ПолучитьФорму("Справочник.Контрагенты.Форма.ФормаГруппы");
    ДанныеФормы = Форма.Объект;
    ЗаполнитьСправочникНаСервере(ДанныеФормы);
    КопироватьДанныеФормы(ДанныеФормы, Форма.Объект);
    Форма.Открыть();

КонецПроцедуры

&НаСервере
Функция ЗаполнитьСправочникНаСервере(ДанныеФормы)

    ОбъектСправочник = ДанныеФормыВЗначение(ДанныеФормы, Тип("СправочникОбъект.Contragents")); 
    ОбъектСправочник = Справочники.Контрагенты.СоздатьГруппу();
    ЗначениеВДанныеФормы(ОбъектСправочник, ДанныеФормы);
    
КонецФункции

На первый взгляд логика кажется вполне рабочей. Мы получаем форму группы ФормаГруппы, затем на сервере преобразуем ее данные в объект, явно создаем группу с помощью метода СоздатьГруппу(), возвращаем всё это в форму и открываем ее. Более того, при отладке непосредственно перед записью свойство Объект.ЭтоГруппа действительно имеет значение Истина.

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

Все дело в архитектуре работы расширения управляемой формы справочника:

  1. Контекст инициализации формы. Метод ПолучитьФорму() без передачи специальных параметров инициализирует форму для создания нового элемента по умолчанию. Тот факт, что мы явно указали имя формы "Справочник.Контрагенты.Form.ФормаГруппы", сообщает платформе лишь о том, какой визуальный шаблон (макет формы) нужно использовать для отображения. Но внутренний тип создаваемого объекта в контексте формы остается «Элемент».
  2. Ограничение на изменение свойства ЭтоГруппа. Тип объекта (группа или элемент) жестко определяется в момент его создания в базе данных и инициализации в форме. Напрямую менять значение свойства ЭтоГруппа у уже созданного в памяти формы объекта нельзя — оно доступно только для чтения.
  3. Сброс значений при записи. Когда мы на сервере принудительно подменили данные формы объектом, созданным через СоздатьГруппу(), мы совершили обходной маневр в обход объектной модели формы. Однако управляемая форма сохранила свой первоначальный контекст — «Форма элемента». При нажатии кнопки «Записать» расширение формы выполняет автоматическую валидацию и синхронизацию данных, принудительно перезаписывая реквизит ЭтоГруппа обратно в значение Ложь в соответствии со своим внутренним состоянием.

Правильное решение: использование параметров формы

Чтобы платформа 1С изначально понимала, что создается именно группа справочника, необходимо правильно инициализировать форму на самом первом этапе. Для этого используется стандартный параметр управляемой формы ЭтоГруппа.

Рассмотрим по шагам, как должен выглядеть корректный код:


&НаКлиенте
Процедура СоздатьГруппу(Команда)
    
    // 1. Создаем структуру параметров и передаем признак создания группы
    ПараметрыФормы = Новый Структура;
    ПараметрыФормы.Вставить("ЭтоГруппа", Истина);
    
    // 2. Получаем форму группы справочника с правильными параметрами инициализации
    Форма = ПолучитьФорму("Справочник.Контрагенты.Форма.ФормаГруппы", ПараметрыФормы);
    
    // 3. Теперь контекст формы изначально настроен на работу с группой.
    // Если требуется выполнить начальное заполнение на сервере:
    ДанныеФормы = Форма.Объект;
    ЗаполнитьГруппуНаСервере(ДанныеФормы);
    КопироватьДанныеФормы(ДанныеФормы, Форма.Объект);
    
    // 4. Открываем форму пользователю
    Форма.Открыть();
    
КонецПроцедуры

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

Передавая структуру Новый Структура("ЭтоГруппа", Истина) в качестве второго параметра метода ПолучитьФорму(), мы указываем платформе вызвать правильный внутренний конструктор. В этом случае расширение управляемой формы сразу настраивается на работу с группой, и при записи объект гарантированно сохранится как папка справочника.

Важные нюансы и сопутствующие параметры

Разберем еще несколько практических аспектов, которые помогут вам при работе с иерархическими справочниками:

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

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

← На главную