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