В процессе разработки на управляемых формах 1С часто возникает задача: при изменении данных в одной колонке табличной части документа необходимо автоматически заполнить другую. Классический пример — подстановка штрихкода, цены или остатка при выборе номенклатуры. Проблема может возникнуть на этапе вызова серверного кода с клиента, особенно если логика получения данных вынесена в модуль менеджера другого объекта, например, регистра сведений.
Рассмотрим реальную ситуацию: есть документ с табличной частью "Товары". При изменении номенклатуры в строке нужно получить её штрихкод из независимого непериодического регистра сведений и подставить в соответствующую колонку. Вся логика получения штрихкода уже написана в экспортной функции в модуле менеджера этого регистра. Вопрос — как правильно вызвать эту функцию из формы документа и какой параметр ей передать?
Давайте проанализируем код, с которым изначально столкнулся разработчик. В модуле менеджера регистра сведений цбкШтрихкоды есть функция для получения штрихкода:
Функция ПолучитьШтрихкод(Ссылка) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| цбкШтрихкоды.Штрихкод КАК Штрихкод
|ИЗ
| РегистрСведений.цбкШтрихкоды КАК цбкШтрихкоды
|ГДЕ
| цбкШтрихкоды.ЕдиницаУчета = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", Ссылка);
Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
Возврат Неопределено;
Иначе
Выборка = Результат.Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.Штрихкод;
КонецЕсли;
КонецЕсли;
КонецФункции
Эта функция ожидает на вход параметр Ссылка, который является ссылкой на измерение регистра ЕдиницаУчета (в данном случае это номенклатура).
Попытка вызова этой функции из формы документа была следующей:
Функция ВыгрузитьШтрихкод()
Штрихкод = РегистрыСведений.цбкШтрихкоды.ПолучитьШтрихкод(Объект.Ссылка);
ШтрихкодУсловие = ?(Штрихкод = Неопределено, "Штрихкод не предусмотрен", Штрихкод);
Возврат ШтрихкодУсловие;
КонецФункции
Здесь допущено две ключевые ошибки:
РегистрыСведений, напрямую из клиентского кода невозможно. Управляемые формы работают в клиент-серверной архитектуре. Клиент (интерфейс пользователя) не имеет прямого доступа к базе данных. Любые операции с данными должны выполняться на сервере. Для этого код на форме нужно разделять директивами компиляции &НаКлиенте и &НаСервере.Объект.Ссылка. Это ссылка на сам документ, а не на номенклатуру, которая была изменена в строке табличной части. Функция в модуле менеджера ожидает получить ссылку на номенклатуру, чтобы найти по ней штрихкод.Чтобы решить задачу корректно, необходимо организовать правильное взаимодействие между клиентом и сервером. Весь процесс можно разбить на три логических шага.
Сначала нужно создать обработчик события ПриИзменении для поля "Номенклатура" в табличной части "Товары". Этот код будет выполняться на клиенте.
Его задача — получить данные текущей строки, в которой пользователь изменил номенклатуру, и инициировать вызов серверной процедуры для получения штрихкода.
&НаКлиенте
Процедура ТоварыНоменклатураПриИзменении(Элемент)
// Получаем доступ к данным текущей строки табличной части
ТекущаяСтрока = Элементы.Товары.ТекущиеДанные;
// Проверяем, что номенклатура выбрана
Если ЗначениеЗаполнено(ТекущаяСтрока.Номенклатура) Тогда
// Вызываем серверную функцию и передаем в нее ссылку на выбранную номенклатуру
// Результат вызова сразу присваиваем полю "ШтрихКод" в этой же строке
ТекущаяСтрока.ШтрихКод = ПолучитьШтрихКодНаСервере(ТекущаяСтрока.Номенклатура);
Иначе
// Очищаем штрихкод, если номенклатуру очистили
ТекущаяСтрока.ШтрихКод = "";
КонецЕсли;
КонецПроцедуры
Важные моменты:
&НаКлиенте указывает, что этот код выполняется на стороне пользователя.Элементы.Товары.ТекущиеДанные — это стандартный способ получить доступ к данным строки табличной части, с которой в данный момент работает пользователь.ТекущаяСтрока.Номенклатура — это как раз та самая ссылка на элемент справочника "Номенклатура", которая нужна нашей серверной функции.Теперь создадим в модуле формы функцию, которая будет выполняться на сервере. Она будет служить "мостом" между клиентом и модулем менеджера регистра. Назовем ее ПолучитьШтрихКодНаСервере.
&НаСервереБезКонтекста
Функция ПолучитьШтрихКодНаСервере(Номенклатура)
// Этот код выполняется на сервере и имеет доступ к базе данных.
// Вызываем экспортную функцию из модуля менеджера, передавая ей полученную с клиента номенклатуру.
Возврат РегистрыСведений.цбкШтрихкоды.ПолучитьШтрихкод(Номенклатура);
КонецФункции
Проанализируем этот код:
&НаСервереБезКонтекста означает, что вызов будет выполнен на сервере. В отличие от &НаСервере, эта директива не передает на сервер весь контекст формы (данные всех реквизитов). Это делает вызов более быстрым и экономным по ресурсам, что является предпочтительным, когда для выполнения операции нужны только переданные параметры.Номенклатура. Это та самая ссылка, которую мы передали с клиента.РегистрыСведений.цбкШтрихкоды.ПолучитьШтрихкод(...). Теперь он абсолютно законен, так как выполняется в серверном контексте.Неопределено) возвращается обратно на клиент, в место вызова.Давайте соберем все воедино и посмотрим на полную картину взаимодействия:
ТоварыНоменклатураПриИзменении.ПолучитьШтрихКодНаСервере, и ей в качестве параметра передается эта ссылка.ПолучитьШтрихКодНаСервере вызывает экспортную функцию ПолучитьШтрихкод из модуля менеджера регистра сведений.ТоварыНоменклатураПриИзменении.ШтрихКод текущей строки табличной части, и пользователь видит результат на форме.Этот подход является стандартным и правильным для реализации подобной логики в управляемых формах 1С. Он четко разделяет код, выполняющийся на клиенте, от кода, работающего с базой данных на сервере, обеспечивая производительность и корректность работы приложения.