При разработке в среде 1С:Предприятие 8.3 на управляемых формах начинающие программисты часто сталкиваются с ситуацией, когда необходимо сравнить значение на форме с реквизитом какого-либо предопределенного элемента или просто получить данные этого элемента непосредственно в клиентском коде. Однако попытка прямого обращения к реквизиту через точку от результата функции ПредопределенноеЗначение приводит к ошибке «Поле объекта не обнаружено».
В этой статье мы подробно разберем, почему так происходит, и рассмотрим эффективные способы решения этой задачи, соблюдая стандарты разработки 1С.
Проанализируем ситуацию, описанную в теме. Разработчик пытается выполнить следующий код на клиенте:
ПредопределенноеЗначение("Справочник.НастройкиДоработок.ВидПроектаИсполнительныхПроизводств").ОбъектыНастроекДоработок
Проблема заключается в архитектуре распределения данных между клиентом и сервером. Функция ПредопределенноеЗначение() на клиенте возвращает ссылку на объект. Ссылка в системе 1С — это уникальный идентификатор (GUID), который хранится в оперативной памяти клиентского приложения. Однако сами данные (значения реквизитов, табличные части) хранятся исключительно в базе данных на сервере.
Важный момент: в тонком и веб-клиенте прямое обращение через точку от ссылки к данным (Ссылка.ИмяРеквизита) запрещено платформой. Это сделано для того, чтобы разработчик не создавал неявных и неконтролируемых обращений к серверу, которые могли бы критически замедлить работу интерфейса при медленном интернет-соединении.
Самый простой и правильный способ получить данные — это кратковременный «поход» на сервер. Чтобы минимизировать нагрузку на систему, рекомендуется использовать директиву &НаСервереБезКонтекста. В этом случае на сервер не передаются данные всей формы, что делает вызов максимально быстрым.
Рассмотрим пример реализации:
&НаКлиенте
Процедура ПроверитьРеквизит()
// Получаем ссылку на предопределенный элемент
НужнаяСсылка = ПредопределенноеЗначение("Справочник.НастройкиДоработок.ВидПроектаИсполнительныхПроизводств");
// Вызываем серверную функцию для получения значения реквизита
ЗначениеРеквизита = ПолучитьРеквизитНаСервере(НужнаяСсылка);
Если Объект.ВидПроекта = ЗначениеРеквизита Тогда
// Ваша логика
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьРеквизитНаСервере(СсылкаНаОбъект)
// На сервере обращение через точку работает, так как есть прямой доступ к БД
Возврат СсылкаНаОбъект.ОбъектыНастроекДоработок;
КонецФункция
Если ваша конфигурация разработана на базе современных типовых решений (УТ 11, ERP, БП 3.0), в ней наверняка присутствует Библиотека стандартных подсистем (БСП). В БСП есть готовый функционал для получения реквизитов любых объектов, который уже оптимизирован и безопасен.
Вместо написания собственных серверных функций, мы можем использовать программный интерфейс общего модуля ОбщегоНазначения. Рассмотрим, как это сделать:
&НаКлиенте
Процедура ПолучитьДанныеЧерезБСП()
НужнаяСсылка = ПредопределенноеЗначение("Справочник.НастройкиДоработок.ВидПроектаИсполнительныхПроизводств");
// Получение одного реквизита через встроенную функцию БСП
// Функция ЗначениеРеквизитаОбъекта сама выполнит переход на сервер
НужноеЗначение = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(НужнаяСсылка, "ОбъектыНастроекДоработок");
Объект.ВидПроекта = НужноеЗначение;
КонецПроцедуры
Если вам нужно получить сразу несколько реквизитов одного и того же предопределенного элемента, используйте функцию ЗначенияРеквизитовОбъекта. Она возвращает структуру, что гораздо эффективнее нескольких отдельных вызовов сервера.
&НаКлиенте
Процедура ПолучитьНесколькоРеквизитов()
НужнаяСсылка = ПредопределенноеЗначение("Справочник.НастройкиДоработок.ВидПроектаИсполнительныхПроизводств");
// Получаем структуру данных за один серверный вызов
СтруктураДанных = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(НужнаяСсылка, "ОбъектыНастроекДоработок, Код, Наименование");
Сообщить(СтруктураДанных.Наименование);
Сообщить(СтруктураДанных.ОбъектыНастроекДоработок);
КонецПроцедуры
Проанализируем ситуацию: если значение реквизита предопределенного элемента меняется редко и оно постоянно требуется на клиенте (например, для управления видимостью элементов формы), постоянные вызовы сервера (даже без контекста) могут быть избыточны.
В таких случаях рекомендуется использовать механизм Функциональных опций. Вы можете привязать значение реквизита справочника к функциональной опции. Преимущество в том, что значения функциональных опций кэшируются платформой на стороне клиента. Вызов ПолучитьФункциональнуюОпцию("ИмяОпции") будет мгновенным и не потребует обращения к серверу при каждом выполнении кода.
Посмотрим на ошибку из сообщения №8 темы форума. Автор пытался использовать менеджер справочника для получения данных:
Справочники[ИмяСправочника] — это обращение к Менеджеру справочника. Через менеджер нельзя напрямую получить значение реквизита конкретного элемента, так как менеджер отвечает за создание новых объектов, поиск и работу со всем классом объектов в целом, а не с конкретной записью.
Также важно помнить о правильном синтаксисе функции ПредопределенноеЗначение(). Имя должно передаваться как строка в формате "Справочник.ИмяСправочника.ИмяПредопределенногоЭлемента". Любая опечатка в этой строке приведет к ошибке во время выполнения программы, которую сложно отловить на этапе компиляции.
Для решения задачи получения данных предопределенного элемента на клиенте необходимо придерживаться следующего алгоритма:
Использование этих подходов сделает ваш код более стабильным, производительным и соответствующим стандартам разработки фирмы «1С».