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

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

Модуль объекта и модуль формы в 1С: в чём разница и где писать код

Разбираем разницу между модулем объекта и модулем формы в 1С: где писать код, контексты исполнения, клиент и сервер, типичные ошибки и примеры.

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

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

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

Где находятся модули и как их открыть

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

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

Важный момент: если у объекта нет ни одной формы, модуль объекта всё равно существует и работает. Объект может создаваться, записываться и проводиться программно, без всякого интерфейса — и весь код модуля объекта при этом выполнится. А вот код модуля формы выполняется только тогда, когда форма открыта.

Контекст исполнения: сервер против клиента

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

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

bsl
&НаКлиенте
Процедура КомандаРассчитать(Команда)
    Результат = РассчитатьНаСервере(Объект.Сумма);
    ПоказатьПредупреждение(, "Сумма с НДС: " + Результат);
КонецПроцедуры

&НаСервере
Функция РассчитатьНаСервере(Сумма)
    Возврат Сумма * 1.2;
КонецФункции

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

Какие события доступны в каждом модуле

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

  • ОбработкаЗаполнения — начальное заполнение при создании объекта;
  • ПередЗаписью и ПриЗаписи — контроль и дополнительные действия при записи;
  • ОбработкаПроведения — формирование движений по регистрам;
  • ОбработкаПроверкиЗаполнения — собственные проверки реквизитов;
  • ПриКопировании, ПриУстановкеНовогоНомера и другие.

В модуле формы доступны события формы и её элементов: ПриОткрытии, ПриСозданииНаСервере, ПередЗакрытием, обработчики изменения полей (ПриИзменении), команд формы, события табличных частей (ПередНачаломДобавления, ПриОкончанииРедактирования). Эти события привязаны к действиям пользователя на экране.

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

Где какие события

Модуль объекта

ОбработкаЗаполнения, ПередЗаписью, ПриЗаписи, ОбработкаПроведения, ОбработкаПроверкиЗаполнения. Срабатывают при любой записи объекта, включая программную.

Модуль формы

ПриОткрытии, ПриСозданииНаСервере, ПриИзменении полей, обработчики команд и табличных частей, ПередЗаписью формы. Срабатывают только при работе через эту форму.

Видимость процедур и взаимодействие между модулями

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

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

Типичный сценарий взаимодействия

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

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

Правила выбора: куда писать код

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

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

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

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

Как выбрать место для кода

Код должен сработать при любой записи объекта, включая программнуюПишите в модуле объекта (ПередЗаписью, ОбработкаПроверкиЗаполнения)
Код реагирует на действие пользователя на формеПишите в модуле формы с директивой &НаКлиенте
Нужен запрос к базе по действию пользователяКлиентский обработчик формы вызывает серверную процедуру (&НаСервере)
Логика нужна и в объекте, и на формеВыносите в общий модуль и вызывайте из обоих мест
Код формирует движения по регистрамТолько модуль объекта, ОбработкаПроведения

Частые ошибки и как их избежать

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

Вторая ошибка — попытка показать сообщение пользователю из модуля объекта через Предупреждение() или Вопрос(). Эти методы там недоступны. Для отказа в записи с объяснением используется Отказ = Истина и вывод сообщения через Сообщить() или механизм ОбработкаПроверкиЗаполнения — платформа сама покажет сообщение пользователю, если запись инициирована интерактивно.

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

Типичные ошибки
01
Проверки данных только в модуле формы — программная запись обходит их, в базе появляются некорректные объекты
02
Вызов Предупреждение() или Вопрос() в модуле объекта — методы недоступны на сервере, код падает с ошибкой
03
Серверные вызовы в цикле на форме — каждый вызов это обращение к серверу, форма зависает
04
Попытка изменить объект на клиенте как в модуле объекта — на клиенте доступны только данные формы, а не объект
05
Дублирование одной логики в модуле объекта и формы — при изменении одно из мест забывают поправить

Как проверить, что код работает в правильном месте

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

Для отладки клиент-серверного взаимодействия в форме полезно поставить точки останова в клиентской и серверной процедурах и проследить порядок вызовов. В конфигураторе отладка серверного кода включается отдельно (Отладка → Подключение → автоматическое подключение серверных процедур), без этого точки останова в серверных процедурах формы могут не срабатывать.

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

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

Срабатывание проверки при программной записи
Норма

Проверка отклоняет запись и из формы, и из кода

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

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

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

Реакция на изменение поля мгновенная или почти мгновенная

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

Видимая пауза при каждом изменении — лишние серверные вызовы

Сообщения об ошибках записи
Норма

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

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

Запись молча не происходит или падает с технической ошибкой

FAQ: частые вопросы о модулях объекта и формы

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

Нет. Модуль объекта выполняется на сервере и ничего не знает о том, открыта ли какая-либо форма. Объект может записываться вообще без интерфейса. Если нужно сообщить пользователю о проблеме, в модуле объекта устанавливают Отказ = Истина и выводят сообщение — платформа доставит его в форму, если запись была интерактивной.

Чем ПередЗаписью в модуле формы отличается от ПередЗаписью в модуле объекта?

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

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

Можно, но только в процедурах с директивой &НаСервере. Клиентские процедуры (&НаКлиенте) выполняются на компьютере пользователя, где нет прямого доступа к базе данных. Поэтому клиентский код обращается к серверной процедуре, та выполняет запрос и возвращает результат.

Где правильно заполнять документ по умолчанию при создании?

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

Что делать, если одна и та же логика нужна и в объекте, и на форме?

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

У регистров есть модуль формы?

У регистров сведений и накопления есть формы списка (и у регистров сведений — форма записи) с собственными модулями формы. Аналогом модуля объекта у регистров служит модуль набора записей, где доступны события ПередЗаписью и ПриЗаписи набора.

Итог

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

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