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