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

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

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

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

---

Почему возникают ошибки при заполнении из общей формы?

Давайте разберем по шагам, почему код автора темы из сообщений вызывал сбои и ошибки в работе программы.

Ошибка 1. «Элемент не выбран!» при вызове метода ПолучитьОбъект()

Эта ошибка возникает по двум причинам:

  1. Реквизит формы, хранящий ссылку (например, РеквизитЭлементЖурнала), пуст на момент вызова кода. Система пытается получить объект базы данных от пустой ссылки Справочники.ЖурналПроверки.ПустаяСсылка().
  2. Пользователь пытается создать новый, еще не записанный в базу данных элемент справочника. У нового объекта еще нет физической ссылки в СУБД, поэтому метод ПолучитьОбъект() закономерно вызывает исключение.

Ошибка 2. «Метод объекта не обнаружен (Записать)» у табличной части

Попытка вызвать метод Записать() напрямую у табличной части формы (например, РеквизитЭлементЖурнала.фактЗнач.Записать()) всегда приводит к ошибке. В управляемых формах реквизиты табличных частей отображаются типом данных ДанныеФормыКоллекция. Это специализированный интерфейсный тип, предназначенный исключительно для связи данных с элементами отображения на экране. У него нет метода сохранения данных в БД. Записать в базу данных можно только целостный прикладной объект (СправочникОбъект или ДокументОбъект).

---

Вариант решения 1. Использование универсального механизма конвертации данных управляемой формы

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

Для реализации этого метода мы задействуем стандартные функции платформы: РеквизитФормыВЗначение и ЗначениеВРеквизитФормы. Эти методы позволяют на сервере временно преобразовать интерфейсные данные формы в полноценный прикладной объект, выполнить с ним любые манипуляции и вернуть обновленный результат обратно на форму.

Рассмотрим пример реализации на форме:


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

&НаКлиенте
Процедура Заполнить(Команда)
    
    // Вызываем серверный обработчик для заполнения и сохранения
    ЗаполнитьНаСервере();
    
КонецПроцедуры

---

Вариант решения 2. Использование основного реквизита формы

Если ваша общая форма спроектирована под работу со справочником, хорошей практикой будет назначить реквизит формы РеквизитЭлементЖурнала (имеющий тип СправочникОбъект.ЖурналПроверки) основным реквизитом формы. Для этого в редакторе формы в свойствах данного реквизита необходимо установить галочку «Основной реквизит» (имя реквизита на форме выделится жирным шрифтом).

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

Проанализируем пример кода для этого сценария:


&НаСервере
Процедура ЗаполнитьНаСервере()
    
    // Очищаем коллекцию данных формы напрямую
    РеквизитЭлементЖурнала.фактЗнач.Очистить();
    
    // Заполняем коллекцию данных формы через экспортный метод
    Справочники.ЖурналПроверки.ЗаполнитьОсновную(РеквизитЭлементЖурнала.фактЗнач);
    
КонецПроцедуры

&НаКлиенте
Процедура Заполнить(Команда)
    
    // Выполняем заполнение коллекции на сервере
    ЗаполнитьНаСервере();
    
    // Записываем саму управляемую форму. 
    // Поскольку реквизит является Основным, платформа автоматически запишет объект в СУБД.
    ЭтотОбъект.Записать(); 
    
КонецПроцедуры

---

Вариант решения 3. Работа через Ссылку (для существующих элементов)

Если на вашей форме реквизит РеквизитЭлементЖурнала хранит только ссылку типа СправочникСсылка.ЖурналПроверки на элемент, который гарантированно уже существует в базе данных, вам необходимо обязательно делать проверку заполнения перед получением объекта.

Давайте посмотрим, как правильно написать процедуру в данном случае:


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

Важное примечание: Если вы изменяете объект непосредственно в базе данных через ссылку (как в Варианте 3), а этот элемент в данный момент отображается на форме пользователя, форма не обновится автоматически. Чтобы пользователь увидел новые строки табличной части, на клиенте может потребоваться вызвать метод оповещения или перечитать данные формы.

← На главную