Как получить реквизиты предопределенного элемента справочника на клиенте в 1С

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

При разработке в среде 1С:Предприятие 8.3 на управляемых формах начинающие программисты часто сталкиваются с ситуацией, когда необходимо сравнить значение на форме с реквизитом какого-либо предопределенного элемента или просто получить данные этого элемента непосредственно в клиентском коде. Однако попытка прямого обращения к реквизиту через точку от результата функции ПредопределенноеЗначение приводит к ошибке «Поле объекта не обнаружено».

В этой статье мы подробно разберем, почему так происходит, и рассмотрим эффективные способы решения этой задачи, соблюдая стандарты разработки 1С.

Разберем причину: почему код не работает на клиенте

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

ПредопределенноеЗначение("Справочник.НастройкиДоработок.ВидПроектаИсполнительныхПроизводств").ОбъектыНастроекДоработок

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

Важный момент: в тонком и веб-клиенте прямое обращение через точку от ссылки к данным (Ссылка.ИмяРеквизита) запрещено платформой. Это сделано для того, чтобы разработчик не создавал неявных и неконтролируемых обращений к серверу, которые могли бы критически замедлить работу интерфейса при медленном интернет-соединении.

Решение 1: Использование серверной функции без контекста

Самый простой и правильный способ получить данные — это кратковременный «поход» на сервер. Чтобы минимизировать нагрузку на систему, рекомендуется использовать директиву &НаСервереБезКонтекста. В этом случае на сервер не передаются данные всей формы, что делает вызов максимально быстрым.

Рассмотрим пример реализации:


&НаКлиенте
Процедура ПроверитьРеквизит()
    // Получаем ссылку на предопределенный элемент
    НужнаяСсылка = ПредопределенноеЗначение("Справочник.НастройкиДоработок.ВидПроектаИсполнительныхПроизводств");
    
    // Вызываем серверную функцию для получения значения реквизита
    ЗначениеРеквизита = ПолучитьРеквизитНаСервере(НужнаяСсылка);
    
    Если Объект.ВидПроекта = ЗначениеРеквизита Тогда
        // Ваша логика
    КонецЕсли;
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьРеквизитНаСервере(СсылкаНаОбъект)
    // На сервере обращение через точку работает, так как есть прямой доступ к БД
    Возврат СсылкаНаОбъект.ОбъектыНастроекДоработок;
КонецФункция

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

Если ваша конфигурация разработана на базе современных типовых решений (УТ 11, ERP, БП 3.0), в ней наверняка присутствует Библиотека стандартных подсистем (БСП). В БСП есть готовый функционал для получения реквизитов любых объектов, который уже оптимизирован и безопасен.

Вместо написания собственных серверных функций, мы можем использовать программный интерфейс общего модуля ОбщегоНазначения. Рассмотрим, как это сделать:


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

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


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

Решение 3: Оптимизация через кэширование (Функциональные опции)

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

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

Типичные ошибки при реализации

Посмотрим на ошибку из сообщения №8 темы форума. Автор пытался использовать менеджер справочника для получения данных:

Справочники[ИмяСправочника] — это обращение к Менеджеру справочника. Через менеджер нельзя напрямую получить значение реквизита конкретного элемента, так как менеджер отвечает за создание новых объектов, поиск и работу со всем классом объектов в целом, а не с конкретной записью.

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

Подведем итоги

Для решения задачи получения данных предопределенного элемента на клиенте необходимо придерживаться следующего алгоритма:

  1. Выяснить, действительно ли нужно обращаться к реквизиту на клиенте или проверку можно перенести целиком в серверную часть логики.
  2. Если данные нужны именно на клиенте, использовать ОбщегоНазначения.ЗначениеРеквизитаОбъекта() (при наличии БСП).
  3. Если БСП отсутствует, написать свою небольшую функцию &НаСервереБезКонтекста, которая будет принимать ссылку и возвращать нужный реквизит.
  4. Никогда не пытаться обращаться к реквизитам через точку от ссылки в клиентских процедурах.

Использование этих подходов сделает ваш код более стабильным, производительным и соответствующим стандартам разработки фирмы «1С».

← На главную