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