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