Как передать значение динамического реквизита между процедурами формы и сохранить его при записи в 1С?

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

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

Почему не работают обычные переменные модуля

Проанализируем архитектуру управляемого приложения. Процедуры с директивой &НаКлиенте и процедуры с директивой &НаСервере выполняются в совершенно разных контекстах — зачастую на физически разных машинах (на компьютере пользователя и на сервере 1С:Предприятия). Переменные модуля формы, объявленные через оператор Перем, не сериализуются и не синхронизируются автоматически между клиентом и сервером. На сервере они инициализируются заново и принимают значение Неопределено.

Для гарантированной передачи данных между контекстами формы необходимо использовать:

  1. Реквизиты формы (в том числе созданные программно через метод ИзменитьРеквизиты) — их значения автоматически передаются между клиентом и сервером в составе контекста формы.
  2. Параметры формы — для передачи данных при открытии или вызове.
  3. Структуру параметров записи — для передачи произвольных значений из клиентского обработчика ПередЗаписью в серверные обработчики записи.

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

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

Посмотрим на корректный пример добавления реквизита и элемента формы:


&НаСервере
Процедура ДобавитьДинамическийРеквизит(ИмяРеквизита, ОписаниеТипаРеквизита, ЗаголовокПоля)
    
    // 1. Создаем массив новых реквизитов формы
    НовыеРеквизиты = Новый Массив;
    НовыйРеквизит = Новый РеквизитФормы(ИмяРеквизита, ОписаниеТипаРеквизита, , ЗаголовокПоля, Истина);
    НовыеРеквизиты.Добавить(НовыйРеквизит);
    
    // 2. Добавляем реквизит в состав формы
    ЭтаФорма.ИзменитьРеквизиты(НовыеРеквизиты);
    
    // 3. Создаем визуальный элемент на форме (передаем строковое имя элемента)
    ИмяЭлемента = "Поле_" + ИмяРеквизита;
    Элемент = ЭтаФорма.Элементы.Добавить(ИмяЭлемента, Тип("ПолеФормы"));
    Элемент.Вид = ВидПоляФормы.ПолеВвода;
    Элемент.ПутьКДанным = ИмяРеквизита;
    Элемент.РастягиватьПоГоризонтали = Ложь;
    
КонецПроцедуры

Обращение к значению программно созданного реквизита

После вызова метода ИзменитьРеквизиты созданный реквизит становится частью контекста формы. Обращаться к нему можно по его имени через обращение к свойствам формы по индексу — ЭтаФорма[ИмяРеквизита]. Это работает как на клиенте, так и на сервере.

Разберем, как прочитать введенное значение в обработчике ПередЗаписью на клиенте и передать его в цепочку серверных событий записи:


&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
    
    ИмяРеквизита = "МойДинамическийРеквизит";
    
    // Получаем значение динамического реквизита формы
    ЗначениеРеквизита = ЭтаФорма[ИмяРеквизита];
    
    // Помещаем значение в структуру ПараметрыЗаписи для передачи на сервер
    ПараметрыЗаписи.Вставить("ЗначениеДляРегистра", ЗначениеРеквизита);
    ПараметрыЗаписи.Вставить("ИмяХарактеристики", ИмяРеквизита);
    
КонецПроцедуры

Запись данных в регистр сведений при сохранении объекта

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

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

Посмотрим на пример безопасного сохранения данных через НаборЗаписей:


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

Альтернативные подходы к реализации

Если задача заключается в хранении дополнительных свойств объектов конфигурации, рассмотрим альтернативные стандартные варианты, не требующие ручного динамического добавления элементов управления:

  1. Подсистема «Свойства» (БСП): В типовых конфигурациях 1С рекомендуется использовать механизм дополнительных реквизитов и сведений Библиотеки Стандартных Подсистем. Он автоматически управляет отображением реквизитов на форме, проверкой заполнения и сохранением в регистр сведений ДополнительныеРеквизитыИСведения.
  2. Табличная часть объекта: Если характеристики жестко связаны с объектом и не требуют вынесения в отдельный регистр сведений, их можно хранить в табличной части самого объекта (например, с колонками Свойство и Значение), что исключает необходимость программного управления транзакциями записи.
← На главную