Как обратиться к перечислению на клиенте в 1С:Управляемые формы и исправить ошибку «Переменная не определена Перечисления»

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При переходе с обычных форм на управляемый интерфейс 1С:Предприятие 8.3 многие разработчики сталкиваются с ситуацией, когда привычный код обращения к перечислениям перестает работать на клиенте. В клиентском модуле попытка написать Перечисления.ТипыНоменклатуры.Услуга приводит к ошибке компиляции: «Переменная не определена (Перечисления)».

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

Почему глобальный контекст «Перечисления» недоступен на клиенте

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

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

Решение проблемы: Использование функции ПредопределенноеЗначение()

Для обращения к предопределенным данным метаданных на клиенте без создания явных серверных процедур в платформу 1С добавлена системная функция ПредопределенноеЗначение().

Рассмотрим синтаксис этой функции:

Результат = ПредопределенноеЗначение("ИмяТипа.ИмяОбъекта.ИмяЗначения");

Критически важный момент: Имя типа метаданных внутри строкового параметра функции всегда указывается в ЕДИНСТВЕННОМ ЧИСЛЕ (Перечисление, Справочник, ПланСчетов и т. д.). Написание типа во множественном числе — одна из самых частых ошибок среди начинающих программистов.

Проанализируем исправленный вариант исходного кода авторского примера:


&НаКлиенте
Процедура ЗапасыКоличествоПриИзменении(Элемент)
    
    ТекущаяСтрока = Элементы.Запасы.ТекущиеДанные;
    Если ТекущаяСтрока = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    Бронь = СформироватьЗапросБронь(ТекущаяСтрока.Номенклатура);        
    СвободныйОстаток = СформироватьОстаток(ТекущаяСтрока.Номенклатура);        
    Ит_Остаток = СвободныйОстаток - Бронь;
    
    Если ТекущаяСтрока.Количество > Ит_Остаток Тогда
        // Используем системную функцию с типом в единственном числе
        ТипУслуга = ПредопределенноеЗначение("Перечисление.ТипыНоменклатуры.Услуга");
        
        Если ТекущаяСтрока.Номенклатура.ТипНоменклатуры <> ТипУслуга Тогда
            ПоказатьПредупреждение(,"Недостаточно товара на складе!");
            ТекущаяСтрока.Количество = 0;
        КонецЕсли;    
    КонецЕсли;
    
КонецПроцедуры

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

Альтернативное решение: Использование Библиотеки Стандартных Подсистем (БСП)

Если ваша конфигурация разработана с использованием Библиотеки Стандартных Подсистем (БСП), рекомендуется использовать специальные функции-обертки из общих модулей. Это считается стандартом чистого кода в экосистеме 1С.

Для обращения к предопределенному значению на клиенте применим следующий код:


ЗначениеУслуга = ОбщегоНазначенияКлиент.ПредопределенныйЭлемент("Перечисление.ТипыНоменклатуры.Услуга");

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

Скрытые проблемы производительности: Чтение реквизитов «через точку» на клиенте

Внимательно проанализируем фрагмент кода из примера:

ТекущаяСтрока.Номенклатура.ТипНоменклатуры

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

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

  1. Добавление колонки в табличную часть формы: При выборе номенклатуры на сервере заполним реквизит ТипНоменклатуры прямо в строке табличной части. В таком случае на клиенте обращение к нему будет происходить мгновенно без вызовов сервера: ТекущаяСтрока.ТипНоменклатуры.
  2. Один контекстный или бесконтекстный серверный вызов: Вместо нескольких последовательных вызовов (расчет остатка, брони и проверка типа номенклатуры) создадим одну серверную функцию, которая за одно обращение вернет все необходимые данные.

Оптимизированный вариант алгоритма

Скомпонуем вычисления и проверки в единый серверный вызов &НаСервереБезКонтекста. Это снизит количество сетевых пакетов между клиентом и сервером с 3–4 до одного, что существенно ускорит работу формы.

Рассмотрим итоговый оптимизированный код:


&НаСервереБезКонтекста
Функция ПолучитьДанныеДляПроверкиКоличества(Номенклатура)
    
    Результат = Новый Структура;
    Результат.Вставить("Заблокировано", Ложь);
    
    // Получаем реквизит номенклатуры на сервере без неявных клиентских вызовов
    ТипНоменклатуры = Номенклатура.ТипНоменклатуры;
    Результат.Вставить("ЭтоУслуга", (ТипНоменклатуры = Перечисления.ТипыНоменклатуры.Услуга));
    
    // Выполняем расчеты остатков и брони на сервере
    Бронь = СформироватьЗапросБроньСервер(Номенклатура);
    СвободныйОстаток = СформироватьОстатокСервер(Номенклатура);
    
    Результат.Вставить("ДоступныйОстаток", СвободныйОстаток - Бронь);
    
    Возврат Результат;
    
КонецФункции

&НаКлиенте
Процедура ЗапасыКоличествоПриИзменении(Элемент)
    
    ТекущиеДанные = Элементы.Запасы.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Или Не ЗначениеЗаполнено(ТекущиеДанные.Номенклатура) Тогда
        Возврат;
    КонецЕсли;
    
    // ОДИН явный серверный вызов вместо множества обращений "через точку"
    ДанныеПроверки = ПолучитьДанныеДляПроверкиКоличества(ТекущиеДанные.Номенклатура);
    
    Если НЕ ДанныеПроверки.ЭтоУслуга И ТекущиеДанные.Количество > ДанныеПроверки.ДоступныйОстаток Тогда
        ПоказатьПредупреждение(,"Введенное количество превышает доступный остаток (" + ДанныеПроверки.ДоступныйОстаток + ")!");
        ТекущиеДанные.Количество = 0;
    КонецЕсли;
    
КонецПроцедуры

Резюме

Для работы с предопределенными данными и перечислениями на клиенте в управляемых формах 1С следует запомнить следующие правила:

  1. Коллекция Перечисления недоступна в клиентском контексте (вызывает ошибку «Переменная не определена»).
  2. Для получения значения перечисления на клиенте используем ПредопределенноеЗначение("Перечисление.ИмяПеречисления.ИмяЗначения").
  3. Тип метаданных в строке параметра обязательно указывается в единственном числе.
  4. Избегаем обращения к реквизитам справочников «через точку» на клиенте. Лучше выносить комплексные проверки и вычисления в один серверный вызов с помощью директивы &НаСервереБезКонтекста.
← На главную