Значение константы в клиентском коде управляемой формы 1С 8.3
Содержание
Получить константу на клиенте напрямую нельзя: менеджер Константы в 1С 8.3 доступен на сервере, в толстом клиенте и во внешнем соединении, но не в тонком и веб-клиенте. Значение читают на сервере и передают на клиент — через реквизит формы, заполненный в ПриСозданииНаСервере, или через серверную функцию.
Ошибка Переменная не определена (Константы) при проверке модуля формы — как раз отсюда. Ниже рабочие способы с готовым кодом, правила кэширования и разбор ошибок, которые чаще всего возникают при обращении к константам из клиентского кода. Тема общая для платформы: способы одинаковы в БП 3.0, ЗУП 3.1, УТ 11 и самописных конфигурациях.
Где выполняется код и почему клиент не видит константы
В управляемом приложении код формы делится на клиентскую и серверную части. Клиент — это компьютер пользователя или браузер. Базы данных у него нет, и все объекты, которые читают данные из базы, на клиенте отсутствуют.
Что недоступно в клиентском контексте тонкого и веб-клиента:
- 🚫 менеджер
Константыи методыПолучить()/Установить(); - 🚫
ПараметрыСеанса; - 🚫 запросы, менеджеры справочников и документов,
ХранилищеЗначения,ТаблицаЗначений; - ✅ доступны: примитивные типы, ссылки,
Структура,Массив,Соответствие, их фиксированные варианты.
Директивы компиляции определяют, где будет выполнена процедура:
| Директива | Где выполняется | Видит данные формы | Видит Константы |
|---|---|---|---|
&НаКлиенте | клиент | да | нет |
&НаСервере | сервер | да (форма передаётся на сервер) | да |
&НаСервереБезКонтекста | сервер | нет | да |
&НаКлиентеНаСервереБезКонтекста | там, откуда вызвали | нет | только в серверной ветке |
В обычном приложении (толстый клиент) Константы.Имя.Получить() работает прямо в клиентском модуле. Если код переносят из старой конфигурации в управляемые формы, такие вызовы перестают компилироваться — это нормальное поведение, а не сбой.
Чтение константы при открытии формы
Самый дешёвый способ: прочитать значение один раз, пока форма создаётся на сервере, и положить его в реквизит формы. Клиент потом читает реквизит без единого обращения к серверу.
Порядок действий:
- Откройте форму в конфигураторе или расширении.
- На вкладке «Реквизиты» добавьте реквизит того же типа, что у константы. Например,
ВалютаРеглс типомСправочникСсылка.Валюты. - В модуле формы заполните его в обработчике
ПриСозданииНаСервере. - В клиентских процедурах обращайтесь к реквизиту как к обычной переменной формы.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ВалютаРегл = Константы.ВалютаРегламентированногоУчета.Получить();
ЛимитСкидки = Константы.МаксимальнаяСкидка.Получить();
КонецПроцедуры
&НаКлиенте
Процедура ПроцентСкидкиПриИзменении(Элемент)
Если Объект.ПроцентСкидки > ЛимитСкидки Тогда
Сообщить(СтрШаблон("Скидка выше допустимой: %1%%", ЛимитСкидки));
Объект.ПроцентСкидки = ЛимитСкидки;
КонецЕсли;
КонецПроцедуры
Имена МаксимальнаяСкидка и ЛимитСкидки здесь условные — подставьте свои. Константа ВалютаРегламентированногоУчета есть в типовых конфигурациях на БСП.
Значение в реквизите — снимок на момент открытия формы. Если администратор поменяет константу, пока форма открыта, пользователь увидит старое значение до повторного открытия.
Форма набора констант
Если форма построена на основном реквизите типа КонстантыНабор (так сделаны формы настроек в типовых), значения уже лежат в данных формы. На клиенте их читают как НаборКонстант.ИмяКонстанты, без серверного вызова. Константа должна быть включена в набор — иначе свойства с её именем не будет.
Булевы константы и функциональные опции
Если константа хранит функциональную опцию (флаг «Использовать склады», «Вести учёт по проектам»), на клиенте можно вызвать ПолучитьФункциональнуюОпцию("ИмяОпции"). Метод доступен в клиентском контексте, а платформа сама кэширует его результат. Для видимости элементов формы опция часто вообще не нужна в коде: достаточно связать элемент с опцией в свойствах.
Серверная функция для сценариев посложнее
Когда значение нужно не при открытии, а по событию — нажатию кнопки, изменению поля, — пишут серверную функцию и вызывают её с клиента.
Функция в модуле формы
Для одной-двух констант хватит функции без контекста. Она не тащит на сервер данные формы, поэтому вызов лёгкий.
&НаКлиенте
Процедура ПроверитьОстатокКредита(Команда)
Лимит = ЛимитКредитаНаСервере();
Если Объект.СуммаДокумента > Лимит Тогда
Сообщить(СтрШаблон("Сумма превышает лимит %1", Формат(Лимит, "ЧДЦ=2")));
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ЛимитКредитаНаСервере()
Возврат Константы.ЛимитКредита.Получить();
КонецФункции
Директива &НаСервере здесь тоже сработает, но тогда на сервер уйдут все реквизиты формы, а с документом на сотни строк это заметно медленнее.
Общий модуль «вызов сервера»
Если константы нужны в нескольких формах, вынесите чтение в общий модуль. Создайте модуль, например, РаботаСКонстантамиВызовСервера, и в свойствах отметьте флажки «Сервер» и «Вызов сервера». Без флажка «Вызов сервера» клиент модуль не увидит.
// Возвращает структуру: ключ — имя константы, значение — её значение.
// ИменаКонстант — строка через запятую: "ЛимитКредита, МаксимальнаяСкидка".
Функция ЗначенияКонстант(Знач ИменаКонстант) Экспорт
Разрешенные = "ЛимитКредита,МаксимальнаяСкидка,ВалютаРегламентированногоУчета";
МассивРазрешенных = СтрРазделить(Разрешенные, ",", Ложь);
Результат = Новый Структура;
Для Каждого Имя Из СтрРазделить(ИменаКонстант, ",", Ложь) Цикл
ИмяКонстанты = СокрЛП(Имя);
Если МассивРазрешенных.Найти(ИмяКонстанты) = Неопределено Тогда
ВызватьИсключение СтрШаблон("Константа %1 недоступна для чтения с клиента", ИмяКонстанты);
КонецЕсли;
Результат.Вставить(ИмяКонстанты, Константы[ИмяКонстанты].Получить());
КонецЦикла;
Возврат Результат;
КонецФункции
Вызов с клиента:
Значения = РаботаСКонстантамиВызовСервера.ЗначенияКонстант("ЛимитКредита, МаксимальнаяСкидка");
Лимит = Значения.ЛимитКредита;
Зачем список разрешённых имён. Экспортная функция модуля «вызов сервера» доступна любому клиентскому коду, включая внешние обработки. Не включайте в такую функцию привилегированный режим и не отдавайте «любую константу по имени» — так легко открыть пароли интеграций или настройки, которые пользователю видеть не положено.
Сравнение способов
| Способ | Когда подходит | Серверных вызовов | Минус |
|---|---|---|---|
Реквизит + ПриСозданииНаСервере | значение нужно всё время работы формы | 0 после открытия | снимок на момент открытия |
НаборКонстант | форма настроек | 0 | только для форм на наборе |
ПолучитьФункциональнуюОпцию | булев флаг-опция | кэшируется платформой | только функциональные опции |
&НаСервереБезКонтекста | редкое чтение по событию | 1 на каждый вызов | не годится для частых событий |
| Общий модуль «вызов сервера» | одна логика для многих форм | 1 на вызов | нужна защита от чтения лишнего |
| Клиентский модуль с кэшем | частое чтение в разных формах | 1 за время жизни кэша | возможна устаревшая копия |
Отзывчивость интерфейса и асинхронность
Каждый серверный вызов синхронный: клиент отправляет запрос и ждёт ответа, интерфейс в это время не реагирует. В локальной сети это незаметно. В веб-клиенте через интернет или на медленном канале серия вызовов превращается в ощутимую паузу.
Ключевые слова Асинх и Ждать, появившиеся в платформе 8.3.18, эту картину не меняют. Они относятся к диалогам и другим асинхронным методам платформы. Обычный вызов серверной функции остаётся синхронным, даже если стоит внутри асинхронной процедуры.
Что реально помогает:
- 📦 Собирайте все нужные значения за один вызов. Три константы — одна функция, возвращающая структуру, а не три функции.
- 🕒 Переносите чтение в
ПриСозданииНаСервере: этот обработчик всё равно выполняется на сервере, лишних обращений не появится. - ⏳ Если тяжёлые данные нужны не сразу, покажите форму, а загрузку отложите через
ПодключитьОбработчикОжидания("ЗагрузитьДанные", 0.1, Истина)вПриОткрытии. Пользователь видит форму, а не «песочные часы». - 🔁 Долгие вычисления на основе констант выносите в фоновое задание. В конфигурациях на БСП для этого есть модуль
ДлительныеОперации.
Сколько вызовов делает форма, видно в замере производительности: в конфигураторе запустите отладку и включите Отладка → Замер производительности. Вызовы сервера при изменении одного поля — повод пересмотреть код.
Кэширование констант на время сеанса
Константы меняются редко, а читаются часто. Поэтому их удобно кэшировать.
Серверный кэш
Общий модуль с признаком «Повторное использование возвращаемых значений» = «На время сеанса» запоминает результат функции для одинаковых параметров. Повторный вызов с теми же параметрами не обращается к базе.
Платформа держит такие значения ограниченное время: кэш сбрасывается примерно через 20 минут после вычисления или через 6 минут после последнего обращения. Так что даже без перезапуска свежие значения со временем подтянутся.
Клиентский кэш
Чтобы не ходить на сервер вовсе, создайте второй модуль, например, РаботаСКонстантамиКлиентПовтИсп:
- Флажок «Клиент (управляемое приложение)» — включён, «Сервер» — выключен.
- «Повторное использование возвращаемых значений» — «На время сеанса».
- Внутри — функция, которая вызывает серверный модуль из предыдущего раздела.
Функция ЗначениеКонстанты(ИмяКонстанты) Экспорт
Значения = РаботаСКонстантамиВызовСервера.ЗначенияКонстант(ИмяКонстанты);
Возврат Значения[ИмяКонстанты];
КонецФункции
Первый вызов РаботаСКонстантамиКлиентПовтИсп.ЗначениеКонстанты("ЛимитКредита") идёт на сервер, следующие возвращают сохранённое значение на клиенте.
Сбросить кэш
принудительно можно методом ОбновитьПовторноИспользуемыеЗначения(). Вызывайте его на клиенте после записи новых значений констант — например, в форме настроек после сохранения.
Параметры работы клиента в БСП
В типовых на БСП значения, которые нужны клиенту постоянно, принято передавать через параметры работы клиента. Их добавляют в переопределяемом модуле ОбщегоНазначенияПереопределяемый, а на клиенте читают через СтандартныеПодсистемыКлиент.ПараметрыРаботыКлиента(). Это удобно для своих доработок в расширении: значение получено один раз при старте и доступно в любой форме.
В кэш не кладите то, что должно быть актуальным до секунды: остатки лимита, номер последнего документа, признак блокировки периода. Их читайте в момент проверки, а окончательную проверку делайте на сервере — например, в ОбработкаПроверкиЗаполнения или ПередЗаписью.
Ошибки при обращении к константам из клиентского кода
Переменная не определена (Константы). Обращение к Константы в процедуре с &НаКлиенте или в клиентском общем модуле. Перенесите чтение на сервер одним из способов выше.
Клиент не видит общий модуль. Проверка модуля ругается на неизвестную переменную с именем модуля. Причина — в свойствах серверного модуля не стоит флажок «Вызов сервера». Отметьте его и обновите конфигурацию базы данных.
Нарушение прав доступа! У роли пользователя нет права «Чтение» на константу. Добавьте право в роль. Если читать константу пользователю нельзя, но значение нужно для расчёта, сделайте расчёт на сервере в привилегированном режиме и верните на клиент только результат, а не саму константу.
Ошибка передачи значения на клиент. Функция вернула ХранилищеЗначения, ТаблицаЗначений или другой тип, которого нет на клиенте. Для константы-хранилища вызовите на сервере .Получить() у самого хранилища и верните структуру или массив. Таблицу значений преобразуйте в массив структур.
Ошибка компиляции в функции без контекста. Внутри &НаСервереБезКонтекста обратились к Объект или реквизиту формы. Передайте нужные данные параметром или смените директиву на &НаСервере.
Старое значение после изменения константы. Сработал кэш: реквизит формы, клиентский модуль повторного использования или параметры работы клиента. Переоткройте форму или вызовите ОбновитьПовторноИспользуемыеЗначения().
Пустая ссылка вместо значения. Константа не заполнена в базе. Обычно это настройки, которые не проходили при начальном заполнении. Проверьте значение в форме настроек и добавьте в код обработку ЗначениеЗаполнено().
Частые вопросы
Можно ли установить значение константы с клиента?
Установить() тоже работает только на сервере. Запишите значение серверной процедурой и после записи сбросьте клиентский кэш методом ОбновитьПовторноИспользуемыеЗначения().Как получить реквизит справочника, который хранится в константе?
Подойдут ли параметры сеанса вместо констант?
ПараметрыСеанса на клиенте тоже недоступны, их читают на сервере так же. Разница в смысле: константа общая для всей базы, параметр сеанса свой у каждого сеанса.Нужно ли что-то менять для веб-клиента?
ПриСозданииНаСервере там особенно оправданы.