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