К статье
Практический материал

Разработка и Конфигурация · 12 мин

1С: как получить значение реквизита объекта на клиенте

Как получить значение реквизита объекта на клиенте в 1С: обращение к данным формы, вызов сервера, реквизиты формы, типичные ошибки и примеры кода.

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

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

Ниже разобраны основные сценарии: чтение реквизита в форме объекта, обращение через объект ДанныеФормыСтруктура, получение реквизита по ссылке через серверный вызов, работа с табличными частями и типичные ошибки, которые приводят к сообщениям «Поле объекта не обнаружено» или «Процедура или функция с указанным именем не определена».

Основной способ: обращение к данным формы объекта

Если код выполняется в модуле формы элемента справочника, документа или другого объекта, реквизиты объекта доступны через основной реквизит формы. По умолчанию он называется Объект, и обращение выглядит так:

// Клиентская процедура в модуле формы объекта

&НаКлиенте

Процедура ПоказатьКонтрагента(Команда)

Контрагент = Объект.Контрагент;

Если ЗначениеЗаполнено(Контрагент) Тогда

Сообщить("Выбран контрагент: " + Контрагент);

КонецЕсли;

КонецПроцедуры

Такой код работает в директиве &НаКлиенте без дополнительных условий: данные формы уже загружены на клиент при открытии формы. Обратите внимание, что тип реквизита формы — не «СправочникОбъект», а специальный тип ДанныеФормыСтруктура, поэтому серверные методы объекта (например, Записать() или ПроверитьЗаполнение()) в клиентском контексте недоступны, хотя чтение реквизитов работает.

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

Чтение реквизита, не выведенного на форму

Частая ситуация: реквизит есть у объекта в конфигурации, но в данные формы он не включён, и обращение Объект.МойРеквизит выдаёт ошибку «Поле объекта не обнаружено». На клиенте это значение получить невозможно — его физически нет в данных формы.

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

Альтернатива без изменения формы — серверный вызов в момент, когда значение нужно. В модуле формы создаётся серверная функция, которая читает объект и возвращает значение:

&НаСервере

Функция ПолучитьСтавкуНДСНаСервере()

Возврат Объект.Ссылка.СтавкаНДС;

КонецФункции

&НаКлиенте

Процедура ПриНажатии(Команда)

Ставка = ПолучитьСтавкуНДСНаСервере();

Сообщить(Ставка);

КонецПроцедуры

Минус этого подхода — каждый вызов идёт на сервер, что замедляет работу при частых обращениях. Если значение нужно постоянно, лучше вывести реквизит в данные формы один раз.

Получение реквизита по ссылке на объект

Когда на клиенте есть только ссылка (например, выбранный элемент в поле ввода или строка списка), значения реквизитов можно получить двумя способами. Первый — обращение через точку: Контрагент.ИНН. В тонком клиенте такая конструкция работает, но приводит к неявному серверному вызову на каждое обращение, что критично в циклах.

Второй, более управляемый способ — явный серверный вызов через общий модуль. Создайте общий модуль с флагами «Сервер» и «Вызов сервера» и добавьте функцию:

// Общий модуль РаботаСДаннымиСервер (Сервер, Вызов сервера)

Функция ЗначениеРеквизитаОбъекта(Ссылка, ИмяРеквизита) Экспорт

Возврат ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, ИмяРеквизита);

КонецФункции

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

Работа с табличными частями и реквизитами формы

Табличная часть объекта в форме доступна как Объект.Товары (коллекция данных формы). Чтобы получить значение реквизита текущей строки, используйте Элементы.Товары.ТекущиеДанные:

&НаКлиенте

Процедура ТоварыПриИзменении(Элемент)

Строка = Элементы.Товары.ТекущиеДанные;

Если Строка <> Неопределено Тогда

Сумма = Строка.Цена * Строка.Количество;

Строка.Сумма = Сумма;

КонецЕсли;

КонецПроцедуры

Помимо реквизитов объекта, у формы могут быть собственные реквизиты формы, созданные разработчиком. Они доступны напрямую по имени: ЭтаФорма.ИтоговаяСумма или просто ИтоговаяСумма. Не путайте их с реквизитами объекта — при записи объекта реквизиты формы не сохраняются в базу.

Если нужно получить значение из формы списка (например, текущую выбранную ссылку), используйте Элементы.Список.ТекущаяСтрока — она вернёт ссылку на текущий элемент, а дальше действуйте по схеме с серверным вызовом, описанной выше.

Типичные ошибки
01
Обращение Объект.Реквизит, когда реквизит не добавлен в данные формы — ошибка «Поле объекта не обнаружено»; решение: добавить реквизит в форму или читать через сервер
02
Вызов Ссылка.ПолучитьОбъект() на клиенте — метод доступен только на сервере, код падает с ошибкой
03
Обращение к реквизиту через точку от ссылки в цикле — сотни серверных вызовов и зависание интерфейса
04
Чтение Элементы.Товары.ТекущиеДанные без проверки на Неопределено — ошибка, когда таблица пустая или фокус не в ней
05
Путаница между реквизитом объекта и реквизитом формы — значение не сохраняется при записи, потому что оно жило только в форме

Оптимизация: снижение числа серверных вызовов

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

&НаСервере

Функция ПолучитьДанныеКонтрагента(КонтрагентСсылка)

Результат = Новый Структура;

Запрос = Новый Запрос(

"ВЫБРАТЬ ИНН, КПП, ЮридическоеФизическоеЛицо

|ИЗ Справочник.Контрагенты

|ГДЕ Ссылка = &Ссылка");

Запрос.УстановитьПараметр("Ссылка", КонтрагентСсылка);

Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда

Результат.Вставить("ИНН", Выборка.ИНН);

Результат.Вставить("КПП", Выборка.КПП);

Результат.Вставить("Вид", Выборка.ЮридическоеФизическоеЛицо);

КонецЕсли;

Возврат Результат;

КонецФункции

Запрос предпочтительнее ПолучитьОбъект(), когда нужно только чтение: он не загружает весь объект со всеми табличными частями и не требует проверки версии данных. ПолучитьОбъект() оправдан, только если планируется изменение и запись объекта на сервере.

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

Маршрут решения

Как выбрать способ

Реквизит выведен в данные формы объектаЧитайте напрямую: Объект.ИмяРеквизита — без серверных вызовов
Реквизит не выведен в форму, значение нужно постоянноДобавьте реквизит в данные формы (без размещения элемента на форме)
Есть только ссылка, значение нужно один разОдин серверный вызов: функция в общем модуле или в форме, возвращающая значение
Нужны реквизиты многих ссылок или несколько реквизитовОдин вызов с запросом или ОбщегоНазначения.ЗначенияРеквизитовОбъектов, возврат структуры
Нужно изменить и записать объектСерверная процедура с ПолучитьОбъект(), изменение и Записать() — всё на сервере

Проверка результата и отладка

После получения значения убедитесь, что оно соответствует ожиданиям по типу и содержимому. Быстрый способ — вывести тип значения: Сообщить(ТипЗнч(Значение)). Для ссылочных реквизитов полезно проверить заполненность через ЗначениеЗаполнено(), чтобы не передавать пустую ссылку в дальнейшую логику.

Если значение приходит с сервера пустым, хотя в карточке объекта оно заполнено, проверьте три вещи: правильно ли указано имя реквизита (учитывается регистр и синонимы не используются), тот ли объект читается (сравните ссылки) и нет ли ограничений прав на уровне записей (RLS), из-за которых запрос возвращает пустой результат.

Для отладки серверных вызовов включите в конфигураторе отладку на сервере (Отладка → Подключение → автоматическое подключение серверных процедур) — иначе точки останова в серверных функциях не сработают.

Контрольные точки

Как проверить результат

Значение реквизита на клиенте
Норма

Тип и содержимое совпадают с данными в карточке объекта

Тревожный признак

Неопределено, пустая ссылка или ошибка «Поле объекта не обнаружено»

Количество серверных вызовов
Норма

Один вызов на логическую операцию, интерфейс отзывчив

Тревожный признак

Вызов в каждой итерации цикла, форма подтормаживает

Серверная функция
Норма

Возвращает структуру или примитивное значение, обрабатывает пустую ссылку

Тревожный признак

Возвращает объект целиком или падает на битой ссылке

Часто задаваемые вопросы

Почему возникает ошибка «Поле объекта не обнаружено» при обращении к реквизиту?

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

Можно ли на клиенте вызвать Ссылка.ПолучитьОбъект()?

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

Чем отличается Объект.Реквизит от Ссылка.Реквизит?

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

Как получить реквизит объекта из другой формы?

Напрямую обращаться к данным чужой формы не рекомендуется. Правильные варианты: передать нужные значения через параметры при открытии формы, вернуть результат через ОповеститьОВыборе/Закрыть с параметром, либо получить ссылку на объект и прочитать реквизиты серверным вызовом.

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

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

Почему серверная функция возвращает пустое значение, хотя реквизит заполнен?

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

Итог

Что важно запомнить

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