К статье
Практический материал

Разработка и Конфигурация · 13 мин

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

Как в 1С получить значение реквизита формы на сервере: ДанныеФормыВЗначение, РеквизитФормыВЗначение, ЭтаФорма. Примеры кода, ошибки и рекомендации.

При разработке управляемых форм в 1С:Предприятие 8.3 разработчик регулярно сталкивается с ситуацией: данные введены пользователем на форме, а обработать их нужно в серверной процедуре — например, записать объект, выполнить запрос или проверить заполнение. Напрямую обратиться к реквизиту формы в серверном контексте нельзя: управляемая форма существует на клиенте, а на сервер передаётся только её «снимок» в виде объекта специального типа.

Ключ к решению — понимание того, как платформа передаёт данные между клиентом и сервером, и какие механизмы преобразования для этого предусмотрены. Основные инструменты — методы РеквизитФормыВЗначение() и ДанныеФормыВЗначение(), а также прямое обращение к реквизитам через ЭтаФорма в серверных процедурах модуля формы.

Ниже разобраны все рабочие способы получения значения реквизита формы на сервере: от простого обращения к реквизиту в контексте формы до передачи данных через параметры и структуры. Отдельно рассмотрены типичные ошибки, которые приводят к сообщениям вида «Процедура или функция с указанным именем не определена» или к потере данных.

Как устроена передача данных формы между клиентом и сервером

Управляемая форма в 1С работает по модели «тонкий клиент — сервер». Визуальная часть и клиентские обработчики выполняются на компьютере пользователя, а бизнес-логика, запросы и запись данных — на сервере. Между ними существует граница вызова, и каждый переход через неё — это сериализация данных, сетевой вызов и десериализация.

Когда выполняется серверная процедура модуля формы (с директивой &НаСервере), платформа передаёт на сервер объект типа УправляемаяФорма, содержащий текущее состояние реквизитов. Поэтому внутри такой процедуры реквизиты формы доступны напрямую — через контекст ЭтаФорма. А вот из общего серверного модуля или модуля объекта обратиться к форме невозможно в принципе: у сервера нет ссылки на неё.

Основной реквизит формы (обычно с именем «Объект») имеет тип ДанныеФормыСтруктура — это не сам объект данных, а его представление. Чтобы получить настоящий ДокументОбъект или СправочникОбъект, требуется преобразование.

Способ 1. Прямое обращение к реквизиту в серверной процедуре формы

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

&НаСервере

Процедура РассчитатьИтогНаСервере()

// Прямое обращение к реквизитам формы

ТекущийКонтрагент = ЭтаФорма.Контрагент;

ТекущаяСумма = ЭтаФорма.СуммаДокумента;

// Можно и без ЭтаФорма — контекст формы подставляется неявно

ЭтаФорма.РезультатРасчета = ТекущаяСумма * 1.2;

КонецПроцедуры

Обращение через ЭтаФорма делает код читаемее и снижает риск конфликта имён с локальными переменными. Если реквизит имеет составной или ссылочный тип (например, СправочникСсылка.Контрагенты), значение будет получено именно как ссылка — без обращения к базе данных. А вот обращение к реквизитам этой ссылки через точку (ЭтаФорма.Контрагент.ИНН) вызовет неявный запрос к БД, что при массовом использовании замедляет работу.

Способ 2. Получение объекта данных через РеквизитФормыВЗначение

Когда нужно не просто прочитать отдельный реквизит, а работать с объектом целиком — вызвать его методы, записать, проверить заполнение, — используется метод формы РеквизитФормыВЗначение(). Он преобразует данные формы в прикладной объект.

&НаСервере

Процедура ЗаписатьСПроверкойНаСервере()

ДокументОбъект = РеквизитФормыВЗначение("Объект");

Если Не ДокументОбъект.ПроверитьЗаполнение() Тогда

Возврат;

КонецЕсли;

ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);

// Возвращаем изменения обратно на форму

ЗначениеВРеквизитФормы(ДокументОбъект, "Объект");

КонецПроцедуры

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

Если после РеквизитФормыВЗначение("Объект") получить значение конкретного поля, это будет уже реквизит объекта данных: ДокументОбъект.Организация, ДокументОбъект.Дата и так далее. Для нового (ещё не записанного) объекта ссылка будет пустой, но все введённые пользователем значения в объекте присутствуют.

Способ 3. ДанныеФормыВЗначение для произвольных реквизитов

Метод ДанныеФормыВЗначение() применяется, когда нужно преобразовать не основной реквизит формы, а, например, таблицу значений или дерево значений, добавленные разработчиком как реквизиты формы. Он работает с текущим элементом коллекции данных формы.

&НаСервере

Функция ПолучитьТаблицуНаСервере()

// Реквизит формы "ТаблицаТоваров" типа ДанныеФормыКоллекция

ТЗ = ЭтаФорма.ТаблицаТоваров.Выгрузить();

ИтоговаяСумма = ТЗ.Итог("Сумма");

Возврат ИтоговаяСумма;

КонецФункции

Для табличных частей объекта отдельное преобразование не нужно: они доступны через основной реквизит, например ЭтаФорма.Объект.Товары, и поддерживают Выгрузить() прямо в серверном контексте. Метод ДанныеФормыВЗначение() чаще встречается при работе с динамическими списками и коллекциями вне контекста основного объекта.

Типичные ошибки
01
Вызов РеквизитФормыВЗначение в клиентской процедуре — метод доступен только на сервере, код упадёт с ошибкой
02
Изменение объекта на сервере без обратного ЗначениеВРеквизитФормы — пользователь не увидит результат
03
Обращение к реквизитам формы из общего модуля — контекст формы там отсутствует, нужна передача параметром
04
Чтение реквизитов ссылки через точку в цикле — каждое обращение идёт в базу данных и резко замедляет работу

Способ 4. Передача значения параметром в общий серверный модуль

Если обработку нужно вынести в общий модуль (что правильно для переиспользуемой логики), реквизит формы передаётся туда обычным параметром. Ограничение: передавать можно только сериализуемые типы — примитивы, ссылки, структуры, массивы. Саму форму или объект ДанныеФормыСтруктура передать нельзя.

&НаСервере

Процедура ОтправитьВОбработкуНаСервере()

// Вариант 1: передать ссылку или значение

Результат = ОбработкаДокументов.ПроверитьКонтрагента(ЭтаФорма.Контрагент);

// Вариант 2: собрать структуру из нескольких реквизитов

ПараметрыОбработки = Новый Структура;

ПараметрыОбработки.Вставить("Контрагент", ЭтаФорма.Контрагент);

ПараметрыОбработки.Вставить("Сумма", ЭтаФорма.СуммаДокумента);

ПараметрыОбработки.Вставить("Дата", ЭтаФорма.Объект.Дата);

Результат = ОбработкаДокументов.ВыполнитьОбработку(ПараметрыОбработки);

КонецПроцедуры

Если общему модулю нужен весь объект, сначала выполните РеквизитФормыВЗначение("Объект") в модуле формы и передайте полученный объект параметром — объекты данных (ДокументОбъект и др.) сериализуются корректно. Это стандартный приём при выносе бизнес-логики из формы.

Порядок действий при выносе логики в общий модуль
  1. 1
    В серверной процедуре формы получите объект: РеквизитФормыВЗначение("Объект")
  2. 2
    Передайте объект или структуру значений параметром в функцию общего модуля
  3. 3
    Выполните обработку в общем модуле и верните результат
  4. 4
    При необходимости обновите форму: ЗначениеВРеквизитФормы(Объект, "Объект")
  5. 5
    Проверьте, что на форме отобразились актуальные данные

Способ 5. Чтение реквизита объекта по ссылке без данных формы

Иногда на форме хранится только ссылка (например, в динамическом списке или в реквизите-параметре), а нужны значения полей этого объекта. В этом случае данные формы вообще не требуются — значения читаются из базы через ссылку или запрос.

&НаСервере

Функция ПолучитьИННКонтрагента(КонтрагентСсылка)

Если Не ЗначениеЗаполнено(КонтрагентСсылка) Тогда

Возврат "";

КонецЕсли;

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ Контрагенты.ИНН КАК ИНН

|ИЗ Справочник.Контрагенты КАК Контрагенты

|ГДЕ Контрагенты.Ссылка = &Ссылка";

Запрос.УстановитьПараметр("Ссылка", КонтрагентСсылка);

Выборка = Запрос.Выполнить().Выбрать();

Возврат ?(Выборка.Следующий(), Выборка.ИНН, "");

КонецФункции

Запрос предпочтительнее обращения через точку (КонтрагентСсылка.ИНН), когда нужно несколько полей или обработка идёт в цикле: один запрос заменяет множество обращений к базе. Для единичного чтения одного поля оба варианта допустимы.

Маршрут решения

Как выбрать способ

Код выполняется в серверной процедуре модуля формы и нужно одно значениеОбратитесь напрямую: ЭтаФорма.ИмяРеквизита
Нужно записать объект или вызвать его методыИспользуйте РеквизитФормыВЗначение("Объект") и затем ЗначениеВРеквизитФормы
Логика находится в общем серверном модулеПередайте значения параметром: ссылкой, объектом или структурой
На форме есть только ссылка, а нужны поля объекта из базыВыполните запрос по ссылке, не трогая данные формы

Проверка результата и отладка

После реализации любого из способов проверьте три вещи. Во-первых, что серверная процедура действительно получила актуальные данные: пользователь мог изменить поле и не покинуть его, но в управляемой форме значение реквизита обновляется сразу при редактировании — в отличие от обычных форм, здесь «незавершённый ввод» проблемой не является.

Во-вторых, убедитесь, что изменения, сделанные на сервере, вернулись на форму. Признак проблемы: в отладчике объект содержит новые значения, а пользователь видит старые. Причина почти всегда в пропущенном вызове ЗначениеВРеквизитФормы().

В-третьих, оцените количество серверных вызовов. Каждая серверная процедура — это сетевой обмен. Если обработчик события «ПриИзменении» вызывает сервер на каждое изменение поля, форма начнёт заметно «подтормаживать» на медленных соединениях. Объединяйте логику в один серверный вызов или выполняйте простые расчёты на клиенте.

Контрольные точки

Как проверить результат

Значение в серверной процедуре
Норма

В отладчике переменная содержит данные, введённые пользователем

Тревожный признак

Значение пустое или устаревшее — проверьте имя реквизита и момент вызова

Отображение после серверной обработки
Норма

Форма показывает обновлённые данные

Тревожный признак

Данные изменились на сервере, но не на форме — нет ЗначениеВРеквизитФормы

Скорость работы формы
Норма

Один серверный вызов на действие пользователя

Тревожный признак

Каскад вызовов сервера в цикле или на каждое событие

Ограничения и частые вопросы безопасности данных

Несколько принципиальных ограничений, которые нельзя обойти. Нельзя получить доступ к форме из фонового задания: фоновое выполнение не имеет контекста интерактивной сессии, поэтому все нужные данные собираются в структуру до запуска задания. Нельзя передать на сервер несериализуемые типы — например, ТабличныйДокумент передаётся, а вот некоторые объекты COM или внешних компонентов — нет.

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

FAQ

Почему в серверной процедуре ошибка «Переменная не определена (ЭтаФорма)»?

Ошибка возникает, когда код с обращением к ЭтаФорма размещён не в модуле формы, а в общем модуле или модуле объекта. Контекст формы существует только в её собственном модуле. Решение — передать нужные значения в общий модуль параметрами.

Чем РеквизитФормыВЗначение отличается от ДанныеФормыВЗначение?

РеквизитФормыВЗначение() — метод формы, преобразующий реквизит по имени (обычно основной реквизит «Объект») в прикладной объект. ДанныеФормыВЗначение() работает с уже полученным элементом данных формы, например со строкой коллекции. На практике для основного реквизита почти всегда используют первый.

Как получить значение реквизита формы на сервере из клиентской процедуры?

Напрямую — никак: клиентская процедура не выполняется на сервере. Нужно вызвать из неё серверную процедуру модуля формы (директива &НаСервере), и уже в ней обратиться к реквизиту через ЭтаФорма. Значения простых типов можно также передать параметром в серверную функцию.

Можно ли передать всю форму в фоновое задание?

Нет. Фоновое задание выполняется вне интерактивной сессии и не имеет доступа к форме. Перед запуском задания соберите необходимые данные в структуру или получите объект через РеквизитФормыВЗначение() и передайте его (или его ссылку) в параметрах метода ФоновыеЗадания.Выполнить().

Почему после изменения объекта на сервере форма показывает старые данные?

Потому что преобразование РеквизитФормыВЗначение() создаёт отдельный объект, не связанный с формой. После изменений вызовите ЗначениеВРеквизитФормы(Объект, "Объект") — тогда данные вернутся в реквизит формы и отобразятся пользователю.

Что быстрее: чтение поля через точку от ссылки или запрос?

Для одного поля единичного объекта разница незаметна. При обращении к нескольким полям или при работе в цикле запрос значительно эффективнее: каждое обращение через точку — отдельное чтение из базы, а запрос забирает всё за одно обращение.

Итог

Что важно запомнить

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