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

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

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

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

В управляемых формах 1С код выполняется в двух контекстах: на клиенте и на сервере. Многие операции — запросы к базе данных, вызовы экспортных процедур модулей объектов, вычисления с большими объёмами данных — доступны только на сервере. Поэтому разработчику регулярно требуется получить значение реквизита формы именно в серверной процедуре, и сделать это нужно правильным способом, иначе возникнет ошибка вызова или лишняя передача данных между клиентом и сервером.

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

Ниже разобраны рабочие способы: чтение основного реквизита через Объект и РеквизитФормыВЗначение, обращение к дополнительным реквизитам, работа с таблицами значений на форме, а также типичные ошибки и способы их диагностики.

Как устроен доступ к данным формы на сервере

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

Обращение к реквизиту внутри модуля формы выполняется по имени, как к свойству: Объект.Ссылка, СуммаДокумента, Товары.Количество(). Ключевое слово ЭтаФорма использовать необязательно, но оно делает код читаемее и снимает неоднозначность, если имя реквизита совпадает с локальной переменной.

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

Чтение основного реквизита: Объект и РеквизитФормыВЗначение

В типовой форме документа, справочника или записи регистра основной реквизит обычно называется Объект. В серверной процедуре его реквизиты читаются напрямую:

&НаСервере

Функция ПолучитьДанныеДокумента()

НомерДокумента = Объект.Номер;

ДатаДокумента = Объект.Дата;

Контрагент = Объект.Контрагент;

Возврат Новый Структура("Номер, Дата, Контрагент",

НомерДокумента, ДатаДокумента, Контрагент);

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

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

&НаСервере

Процедура ПровестиДокументНаСервере()

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

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

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

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

Обратная операция — ЗначениеВРеквизитФормы — возвращает изменения в форму, чтобы пользователь увидел актуальное состояние. Без неё изменения, сделанные через объект, на экране не отобразятся, а при следующем серверном вызове могут быть потеряны.

Чтение дополнительных реквизитов формы

Дополнительные реквизиты — те, что разработчик добавил в палитре реквизитов формы (панель «Реквизиты» в редакторе формы). На сервере они доступны по имени точно так же, как на клиенте:

&НаСервере

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

ИтоговаяСумма = 0;

Для Каждого Строка Из Товары Цикл

ИтоговаяСумма = ИтоговаяСумма + Строка.Сумма;

КонецЦикла;

ЭтаФорма.ИтогоПоДокументу = ИтоговаяСумма;

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

Здесь Товары и ИтогоПоДокументу — реквизиты формы. Табличная часть объекта и реквизит типа «ТаблицаЗначений» на форме обходятся обычным циклом Для Каждого, строки имеют тип ДанныеФормыЭлементКоллекции, но обращение к колонкам идёт по именам, как у обычной строки таблицы значений.

Если реквизита с таким именем не существует, платформа выдаст ошибку «Поле объекта не обнаружено». Поэтому при динамическом обращении (когда имя реквизита хранится в строковой переменной) используйте конструкцию ЭтаФорма[ИмяРеквизита] — она позволяет работать с реквизитами, имена которых известны только во время выполнения.

Получение реквизита формы из общего модуля и внешнего кода

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

&НаСервере

Процедура ОтправитьВОбщийМодуль()

ПараметрыРасчета = Новый Структура;

ПараметрыРасчета.Вставить("Ссылка", Объект.Ссылка);

ПараметрыРасчета.Вставить("Организация", Объект.Организация);

Результат = ОбщегоНазначенияСервер.ВыполнитьРасчет(ПараметрыРасчета);

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

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

Типичные ошибки
01
Попытка обратиться к элементу формы (Элементы.ПолеВвода) на сервере — элементы доступны только на клиенте, будет ошибка вызова.
02
Изменение объекта после РеквизитФормыВЗначение без ЗначениеВРеквизитФормы — изменения теряются, форма показывает старые данные.
03
Передача всей формы или ДанныеФормы в общий модуль — такие типы нельзя передавать между контекстами, нужно передавать примитивные значения или структуры.
04
Чтение реквизита в цикле с вызовом сервера на каждой итерации — каждый вызов это обращение к серверу, собирайте данные за один вызов.

Директивы компиляции и контекст вызова

Директива перед процедурой определяет, где она выполняется и что в ней доступно. Для чтения реквизитов формы на сервере используются два варианта:

  • &НаСервере — полный контекст формы на сервере: доступны реквизиты, методы РеквизитФормыВЗначение, ЗначениеВРеквизитФормы. При вызове с клиента данные формы передаются на сервер целиком.
  • &НаСервереБезКонтекста — форма как объект недоступна, реквизиты по имени не читаются. Такие процедуры быстрее (нет передачи данных формы), но подходят только для работы с базой по ссылке или с параметрами, переданными явно.
  • &НаКлиенте — реквизиты формы доступны, но серверные механизмы (запросы, объекты) — нет.

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

&НаКлиенте

Процедура Пересчитать(Команда)

ПересчитатьНаСервере();

// результат уже в реквизитах формы

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

&НаСервере

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

ЭтаФорма.Результат = Объект.Количество * Объект.Цена;

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

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

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

После внедрения кода проверьте три вещи. Во-первых, откройте форму и выполните действие: значение в реквизите должно обновиться на экране. Если реквизит не выведен на форму, временно добавьте поле или выведите значение через Сообщить в серверной процедуре — сообщение появится у пользователя после вызова.

Во-вторых, проверьте поведение при повторном вызове: данные не должны «откатываться». Откат — верный признак того, что изменения делались в копии от РеквизитФормыВЗначение без обратной записи в форму.

В-третьих, проверьте работу под пользователем с ограниченными правами. Серверный код выполняется с правами текущего пользователя, и обращение к данным, на которые нет прав (например, чтение ссылочного поля через точку — «разыменование»), может вызвать ошибку доступа, которой не было у разработчика под полными правами.

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

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

Значение реквизита после серверного вызова
Норма

Отображается актуальное значение, сохраняется при повторных вызовах

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

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

Ошибки при выполнении
Норма

Процедура выполняется без сообщений об ошибках

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

"Поле объекта не обнаружено" — неверное имя реквизита

Работа под ограниченными правами
Норма

Код работает у обычного пользователя

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

Ошибка доступа при разыменовании ссылок

Ограничения и альтернативные подходы

Главное ограничение: каждый вызов серверной процедуры с контекстом формы — это передача данных формы по сети. В тонком клиенте и веб-клиенте при больших табличных частях это заметно влияет на отзывчивость. Если нужно прочитать одно поле по ссылке, дешевле использовать &НаСервереБезКонтекста и передать только ссылку.

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

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

Сравнение способов

ЭтаФорма.ИмяРеквизита (&НаСервере)

Быстро и просто для чтения и записи данных формы. Не даёт методов объекта базы.

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

Полный объект с методами: запись, проведение, обработчики. Требует обратного преобразования и тяжелее по ресурсам.

&НаСервереБезКонтекста + ссылка

Минимальная нагрузка, нет доступа к реквизитам формы — только к базе по переданным параметрам.

Итог

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

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

Частые вопросы

Почему на сервере недоступны Элементы формы?

Элементы формы — это визуальные контролы, они существуют только в клиентском процессе. На сервер передаются только данные (реквизиты). Если на сервере нужно значение поля ввода — читайте связанный с ним реквизит формы, а не сам элемент.

Чем отличается Объект от РеквизитФормыВЗначение("Объект")?

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

Можно ли получить реквизит формы в процедуре &НаСервереБезКонтекста?

Нет. В таких процедурах контекст формы отсутствует, и обращение к реквизиту вызовет ошибку. Передайте нужные значения параметрами или измените директиву на &НаСервере, если требуется доступ к данным формы.

Как обратиться к реквизиту, имя которого хранится в переменной?

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

Почему изменения, сделанные на сервере, не видны на форме?

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

Влияет ли чтение реквизитов на сервере на производительность?

Само чтение быстрое, но вызов серверной процедуры с контекстом формы передаёт все данные формы между клиентом и сервером. При больших табличных частях и частых вызовах это заметно. Оптимизация — группировать обращения в один серверный вызов и использовать &НаСервереБезКонтекста, где данные формы не нужны.