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

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

Как передать реквизит формы в модуль объекта в 1С

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

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

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

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

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

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

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

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

Способ 1. Передать значение параметром в экспортную процедуру объекта

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

В модуле объекта документа:

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

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

СтрокаТовары.СуммаНДС = СтрокаТовары.Сумма * СтавкаНДС / 100;

КонецЦикла;

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

В модуле формы (серверная процедура):

&НаСервере

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

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

ДокументОбъект.ЗаполнитьПоСтавке(СтавкаНДСФормы);

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

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

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

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

Способ 2. Записать значение в реквизит объекта перед вызовом

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

&НаСервере

Процедура ВыполнитьРасчетНаСервере()

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

ДокументОбъект.КоэффициентРасчета = КоэффициентФормы;

ДокументОбъект.ВыполнитьРасчет();

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

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

Минус подхода — изменение метаданных и лишнее поле в базе данных, если значение носит временный, «интерфейсный» характер. Используйте его, когда значение действительно должно храниться вместе с документом или участвует в проведении.

Способ 3. Вынести логику в общий модуль

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

// Общий модуль РасчетыСервер

Функция РассчитатьСуммуСоСтавкой(Сумма, Ставка) Экспорт

Возврат Сумма + Сумма * Ставка / 100;

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

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

Сравнение вариантов

Параметр экспортной процедуры объекта

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

Реквизит объекта

Подходит, если значение должно храниться в базе. Минус — изменение метаданных

Общий модуль

Лучший вариант для разделяемой логики. Не подходит, если нужен доступ к ЭтотОбъект

Передача табличной части и коллекций

Табличную часть формы нельзя передать в модуль объекта «как есть» — тип ДанныеФормыКоллекция несовместим с табличной частью объекта. Правильный путь — преобразовать форму в объект целиком: табличные части при этом переносятся автоматически, и в модуле объекта доступны как обычно.

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

&НаСервере

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

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

Документы.ЗаказПокупателя.ОбработатьСтроки(ТЗ); // вызов модуля менеджера

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

Типичные ошибки и ограничения

Самая частая ошибка — вызов процедуры объекта из клиентского контекста. Директива &НаКлиенте не имеет доступа к РеквизитФормыВЗначение и к модулю объекта, компилятор выдаст «Процедура или функция с указанным именем не определена». Решение — серверная процедура-обёртка в форме.

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

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

Типичные ошибки
01
Вызов РеквизитФормыВЗначение на клиенте — метод доступен только на сервере
02
Пропуск ЗначениеВРеквизитФормы — изменения объекта не попадают в форму
03
Обращение к реквизиту формы из модуля объекта — ошибка «Поле объекта не обнаружено»
04
Изменение реквизита формы без возврата объекта при работе через параметр-структуру

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

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

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

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

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

Компиляция модулей
Норма

Нет ошибок о неопределённых процедурах

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

«Процедура или функция не определена» — неверный контекст или нет Экспорт

Данные на форме после вызова
Норма

Значения пересчитались

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

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

Запись и повторное открытие
Норма

Изменения сохранились

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

Данные потеряны — объект не возвращён в форму перед записью

FAQ

Можно ли обратиться к модулю объекта напрямую из клиентской процедуры формы?

Нет. Модуль объекта исполняется на сервере, поэтому из клиентской процедуры нужно вызвать серверную процедуру формы, которая уже получит объект и обратится к его модулю.

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

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

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

Соберите их в структуру: Параметры = Новый Структура("Ставка, Коэффициент", СтавкаФормы, КоэффициентФормы) — и передайте структуру одним параметром в экспортную процедуру объекта.

Нужно ли записывать объект после вызова процедуры из формы?

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

Можно ли передать реквизит формы в модуль менеджера объекта?

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

Почему возникает ошибка «Поле объекта не обнаружено» при обращении к реквизиту?

Модуль объекта пытается обратиться к реквизиту, которого нет в метаданных объекта — обычно это реквизит, добавленный только в форму. Передайте такое значение параметром процедуры вместо обращения через ЭтотОбъект.

Итог

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

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