Константа в клиентском коде управляемой формы: как получить значение

· 9 мин

Содержание

Напрямую обратиться к константе на клиенте 1С 8.3 нельзя: менеджер Константы есть только на сервере, в толстом клиенте и во внешнем соединении. В тонком и веб-клиенте значение константы получают через сервер: функцией с директивой &НаСервереБезКонтекста, через реквизит формы, заполненный при создании, или через общий модуль с флагом «Вызов сервера».

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

Почему клиентский код не видит Константы

В управляемом приложении код делится на клиентский и серверный. На клиенте нет базы данных, а значит нет и менеджеров, которые читают из неё данные: Константы, Справочники, Документы, РегистрыСведений, ПараметрыСеанса.

Если написать в клиентской процедуре формы:

&НаКлиенте
Процедура ПроверитьНастройку(Команда)
	Если Константы.ИспользоватьВалютныйУчет.Получить() Тогда
		// ...
	КонецЕсли;
КонецПроцедуры

конфигуратор при проверке модуля выдаст Переменная не определена (Константы). Это не ошибка прав и не сбой базы, а граница контекста: имя Константы в клиентском контексте просто не существует.

Что доступно где:

ОбъектТонкий и веб-клиентСерверТолстый клиент (обычное приложение)
Константы.Имя.Получить()нетдада
ПараметрыСеанса.Имянетдада
ПолучитьФункциональнуюОпцию()дадада
Реквизиты формыдадада
Экспортные переменные модуля приложенияданетда

В толстом клиенте обычного приложения Константы работают прямо в клиентском коде. Поэтому старый код из конфигураций на обычных формах при переносе в управляемые формы ломается именно на этом месте.

Отсюда общий принцип. Клиент получает значение константы одним из трёх путей: идёт за ним на сервер, получает его заранее вместе с формой или берёт из кэша, который заполнили на сервере.

Способ 1. Серверная функция в модуле формы

Самый прямой путь — функция формы, которая выполняется на сервере и возвращает значение.

&НаКлиенте
Процедура ПроверитьНастройку(Команда)
	Если ИспользуетсяВалютныйУчет() Тогда
		Сообщить("Валютный учёт включён");
	КонецЕсли;
КонецПроцедуры

&НаСервереБезКонтекста
Функция ИспользуетсяВалютныйУчет()
	Возврат Константы.ИспользоватьВалютныйУчет.Получить();
КонецФункции

Почему &НаСервереБезКонтекста, а не &НаСервере:

  • 📦 &НаСервере передаёт на сервер и обратно все данные формы: реквизиты, таблицы, состояние элементов. На форме документа с табличной частью в 500 строк это ощутимо.
  • ⚡ &НаСервереБезКонтекста не тащит форму. Передаются только параметры и возвращаемое значение.
  • 🚫 Плата за скорость: внутри такой функции нельзя обратиться к реквизитам формы и ЭтаФорма.

Для чтения константы контекст формы не нужен, поэтому &НаСервереБезКонтекста подходит почти всегда.

Несколько констант за один вызов

Каждый вызов сервера — отдельный сетевой запрос. Пять функций по одной константе — пять запросов. Собирайте значения в структуру:

&НаСервереБезКонтекста
Функция НастройкиУчета()
	Результат = Новый Структура;
	Результат.Вставить("ВалютныйУчет", Константы.ИспользоватьВалютныйУчет.Получить());
	Результат.Вставить("ОсновнаяВалюта", Константы.ВалютаРегламентированногоУчета.Получить());
	Результат.Вставить("ДатаЗапрета", Константы.ДатаЗапретаИзменения.Получить());
	Возврат Результат;
КонецФункции

Имена констант здесь условные: возьмите те, что есть в вашей конфигурации, из ветки Константы дерева метаданных.

На клиент можно вернуть примитивные типы, ссылки, Структуру, Массив, ФиксированнуюСтруктуру. Объекты, которые живут только на сервере (например, Запрос или ТаблицаЗначений), на клиент не передаются — преобразуйте их в массив структур.

Способ 2. Реквизит формы, заполненный при создании

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

  1. В редакторе формы на вкладке «Реквизиты» добавьте реквизит, например ВалютныйУчет с типом Булево. На форму его выводить не нужно.
  2. В обработчике ПриСозданииНаСервере заполните его:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	ВалютныйУчет = Константы.ИспользоватьВалютныйУчет.Получить();
КонецПроцедуры
  1. В клиентском коде используйте реквизит как обычную переменную:
&НаКлиенте
Процедура ВалютаПриИзменении(Элемент)
	Если ВалютныйУчет Тогда
		ПересчитатьКурс();
	КонецЕсли;
КонецПроцедуры

ПриСозданииНаСервере выполняется в том же серверном вызове, что и открытие формы. Отдельного обращения к серверу не будет.

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

Как обновить реквизит без переоткрытия формы

Если константу меняют в том же сеансе, например в форме настроек, открытые формы можно предупредить оповещением. Форма настроек после записи вызывает:

&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
	Оповестить("ИзмененыНастройкиУчета");
КонецПроцедуры

А рабочая форма ловит это событие и перечитывает значение одним серверным вызовом:

&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
	Если ИмяСобытия = "ИзмененыНастройкиУчета" Тогда
		ВалютныйУчет = ИспользуетсяВалютныйУчет();
	КонецЕсли;
КонецПроцедуры

Оповещение работает только внутри одного сеанса. Пользователь на другом компьютере увидит новое значение после переоткрытия формы.

Тот же приём работает для видимости элементов. Если поле нужно скрыть, когда выключена настройка, сделайте это сразу в ПриСозданииНаСервере через Элементы.ИмяПоля.Видимость, а не на клиенте после открытия.

Способ 3. Общий модуль с вызовом сервера и повторным использованием

Когда одна и та же константа нужна в десятках форм, копировать серверную функцию в каждую неудобно. Вынесите её в общий модуль.

  1. Создайте общий модуль, например НастройкиСервер.
  2. В его свойствах включите флажки «Сервер» и «Вызов сервера».
  3. Добавьте экспортную функцию:
Функция ЗначениеКонстанты(ИмяКонстанты) Экспорт
	Возврат Константы[ИмяКонстанты].Получить();
КонецФункции
  1. С клиента вызывайте её по имени модуля:
&НаКлиенте
Процедура Проверить(Команда)
	ДатаЗапрета = НастройкиСервер.ЗначениеКонстанты("ДатаЗапретаИзменения");
КонецПроцедуры

Без флажка «Вызов сервера» модуль виден только из серверного кода, и с клиента вы получите ту же Переменная не определена.

Кэш на время сеанса

Чтобы не ходить на сервер за неизменной настройкой при каждом обращении, сделайте второй модуль с повторным использованием.

Свойство общего модуляЗначение
ИмяНастройкиПовтИсп (суффикс ПовтИсп — принятое соглашение)
Сервервключено
Вызов серверавключено
Повторное использование возвращаемых значений«На время сеанса»
Функция ВалютныйУчетИспользуется() Экспорт
	Возврат Константы.ИспользоватьВалютныйУчет.Получить();
КонецФункции

Первый вызов НастройкиПовтИсп.ВалютныйУчетИспользуется() идёт на сервер. Следующие вызовы с теми же параметрами платформа отдаёт из кэша без сетевого запроса.

Правила для таких функций:

  • 🔒 Возвращайте неизменяемые значения: примитивы, ссылки, ФиксированнуюСтруктуру, ФиксированныйМассив. Обычную структуру из кэша код может случайно изменить, и «испорченное» значение увидят все последующие вызовы.
  • 🧹 Платформа вправе сбросить кэш сама, поэтому не храните в нём то, что нельзя пересчитать.
  • 🔄 После изменения константы сбросьте кэш методом ОбновитьПовторноИспользуемыеЗначения(). Он доступен и на клиенте.

Функциональные опции: константа без вызова сервера

Если константа типа Булево включает или выключает часть функциональности, её удобнее привязать к функциональной опции. Метод ПолучитьФункциональнуюОпцию() доступен на клиенте, а платформа сама кэширует значения опций.

  1. В ветке Общие → Функциональные опции создайте опцию.
  2. В свойстве «Хранение» укажите константу.
  3. В клиентском коде:
&НаКлиенте
Процедура Проверить(Команда)
	Если ПолучитьФункциональнуюОпцию("ИспользоватьВалютныйУчет") Тогда
		// ...
	КонецЕсли;
КонецПроцедуры

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

В типовых конфигурациях на БСП многие настройки уже оформлены функциональными опциями. Прежде чем писать серверный вызов, загляните в ветку Функциональные опции и поищите опцию с хранением в нужной константе.

После изменения константы, связанной с опцией, интерфейс открытых окон перестраивается не сразу. Вызов ОбновитьИнтерфейс() применяет изменения в текущем сеансе.

Параметры сеанса и значения, рассчитанные при входе

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

Как с ними работать:

  • 🖥️ Значения устанавливаются на сервере в модуле сеанса, в процедуре УстановкаПараметровСеанса. Если параметр ещё не заполнен, платформа вызовет эту процедуру при первом обращении.
  • 📡 Читаются с клиента так же, как константы: серверной функцией или функцией общего модуля с флагом «Вызов сервера».
  • ✍️ Записать параметр сеанса из клиентского кода нельзя. Только серверная процедура, и пользователю нужно право на установку этого параметра.

Кэш на весь сеанс в модуле приложения

Значения, которые нужны всему клиентскому коду с момента входа, можно получить один раз при старте и держать в экспортной переменной модуля управляемого приложения:

// Модуль управляемого приложения
Перем НастройкиКлиента Экспорт;

Процедура ПриНачалеРаботыСистемы()
	НастройкиКлиента = НастройкиСервер.НастройкиДляКлиента();
КонецПроцедуры

Серверная функция НастройкиДляКлиента() собирает константы и параметры сеанса в ФиксированнуюСтруктуру. Дальше любая клиентская процедура обращается к НастройкиКлиента.ВалютныйУчет без единого вызова сервера.

В конфигурациях на БСП так уже устроены «параметры работы клиента». Их дополняют в процедуре ОбщегоНазначенияПереопределяемый.ПриДобавленииПараметровРаботыКлиента, а с клиента читают через СтандартныеПодсистемыКлиент.ПараметрыРаботыКлиента(). Свою переменную в модуле приложения типовой конфигурации добавлять не нужно: это лишнее изменение при обновлении.

Какой способ выбрать и сколько стоит вызов сервера

Каждое обращение к серверу из тонкого клиента — сетевой запрос. В локальной сети он почти незаметен. Через интернет, веб-клиент или медленный канал задержка каждого вызова складывается, и форма с пятью отдельными обращениями за константами открывается заметно дольше.

Как часто меняется значение и где оно нужно?

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

Ещё три правила экономии:

  • 🧩 Не вызывайте сервер в цикле. Читать константу внутри Для Каждого по строкам таблицы — классический источник тормозов.
  • 📦 Не возвращайте с сервера больше, чем нужно. Константа с типом ХранилищеЗначения может содержать мегабайты: распакуйте её на сервере методом Получить() и верните клиенту только нужную часть.
  • ⏱️ Не используйте &НаСервере там, где хватает &НаСервереБезКонтекста.

Ошибки при обращении к константе из клиентского кода

Диагностика: выберите симптом

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

Частые вопросы

Можно ли записать константу из клиентского кода?
Напрямую нет. Вызовите серверную процедуру, которая выполнит Константы.Имя.Установить(Значение). У пользователя должно быть право «Изменение» на константу.
Почему в обычной форме код с Константами работал, а в управляемой нет?
Обычные формы выполняются в толстом клиенте, где менеджер Константы доступен. Управляемые формы в тонком и веб-клиенте разделяют клиентский и серверный код.
Как обратиться к константе из модуля команды?
Обработчик команды выполняется на клиенте. Используйте функцию общего модуля с флагом «Вызов сервера» или функциональную опцию.
Работает ли ПолучитьФункциональнуюОпцию() в веб-клиенте?
Да. Метод доступен в тонком, веб- и мобильном клиенте, значения платформа кэширует сама.
Как прочитать константу на форме набора констант?
У формы констант основной реквизит имеет тип КонстантыНабор. Значения доступны на клиенте как его поля, например НаборКонстант.ИспользоватьВалютныйУчет, без вызова сервера.