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