Разработка и Конфигурация · 10 мин
Как получить значение реквизита на клиенте в 1С
Как получить значение реквизита объекта на клиенте в 1С: чтение реквизитов формы, текущей строки таблицы, вызов сервера и обмен данными с клиентом.
В управляемых формах 1С клиент и сервер работают раздельно: на клиенте доступен только тонкий набор данных формы, а прямой доступ к базе данных запрещён. Поэтому вопрос «как получить значение реквизита на клиенте» почти всегда сводится к выбору одного из трёх путей: прочитать реквизит, уже загруженный в данные формы, взять значение из текущей строки таблицы или запросить значение с сервера через серверный вызов.
Ошибки в этой теме обычно связаны с тем, что разработчик пытается обратиться к объекту, которого на клиенте физически нет: например, к реквизиту справочника через ссылку. Понимание того, какие данные реально присутствуют на клиенте, избавляет от типичных ошибок компиляции и лишних серверных вызовов.
Ниже разобраны рабочие приёмы для управляемого приложения: чтение реквизитов объекта формы, работа с текущими данными табличной части, серверные вызовы и обмен контекстом между клиентом и сервером.
Что вообще доступно на клиенте в управляемой форме
В управляемом приложении код с директивой &НаКлиенте выполняется вне контекста базы данных. Клиент «видит» только данные формы: реквизиты формы, таблицы формы, элементы управления. Запросы, менеджеры объектов (Справочники, Документы), прямые обращения к реквизитам через точку от ссылки — всё это доступно только на сервере.
Ключевое следствие: если реквизит объекта выведен в данные формы (есть в дереве реквизитов формы), его значение уже находится на клиенте, и читать его можно без всяких серверных вызовов. Если реквизита в форме нет, его нужно либо добавить в данные формы, либо получать на сервере.
Как прочитать реквизит объекта, уже загруженного в форму
Самый частый случай: форма документа или элемента справочника. Основной реквизит такой формы обычно называется Объект, и все реквизиты объекта, добавленные в форму, доступны через него напрямую:
&НаКлиенте
Процедура КонтрагентПриИзменении(Элемент)
ТекущийКонтрагент = Объект.Контрагент;
Комментарий = Объект.Комментарий;
Сообщить("Выбран контрагент: " + ТекущийКонтрагент);
КонецПроцедуры
Здесь Объект.Контрагент — это уже значение на клиенте. Никаких дополнительных вызовов не требуется. То же относится к реквизитам формы, добавленным вручную: они читаются по имени напрямую, например ЭтаФорма.ИтоговаяСумма или просто ИтоговаяСумма.
Важный нюанс: если реквизит объекта не добавлен в дерево реквизитов формы (разработчик убрал его или он не входит в состав данных формы по умолчанию), обращение Объект.НекийРеквизит вызовет ошибку «Поле объекта не обнаружено». Проверить состав данных можно в редакторе формы, на вкладке «Реквизиты».
Как получить значение реквизита текущей строки таблицы
Табличные части и динамические списки на клиенте читаются через свойство ТекущиеДанные элемента формы. Это стандартный приём для обработчиков событий таблиц:
&НаКлиенте
Процедура ТоварыПриИзменении(Элемент)
Строка = Элементы.Товары.ТекущиеДанные;
Если Строка = Неопределено Тогда
Возврат;
КонецЕсли;
Строка.Сумма = Строка.Количество * Строка.Цена;
КонецПроцедуры
Обязательно проверяйте ТекущиеДанные на Неопределено: когда таблица пуста или фокус не установлен, свойство возвращает Неопределено, и обращение к полю приведёт к ошибке.
Если нужна строка не текущая, а по индексу, используйте коллекцию данных формы: Объект.Товары[0] для первой строки табличной части. Для обхода всех строк подходит цикл Для Каждого Строка Из Объект.Товары Цикл.
- 1Получите строку: Строка = Элементы.Товары.ТекущиеДанные
- 2Проверьте, что Строка <> Неопределено
- 3Обратитесь к полю: Строка.Цена или Строка["Цена"]
- 4Проверьте результат в отладчике или через Сообщить()
Как получить реквизит по ссылке через серверный вызов
Когда на клиенте есть только ссылка (например, выбрали контрагента, а нужно узнать его ИНН), значение запрашивают на сервере. Для этого в модуле формы создают функцию с директивой &НаСервере или &НаСервереБезКонтекста:
&НаКлиенте
Процедура КонтрагентПриИзменении(Элемент)
ИНН = ПолучитьИННКонтрагента(Объект.Контрагент);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьИННКонтрагента(КонтрагентСсылка)
Возврат КонтрагентСсылка.ИНН;
КонецФункции
Директива БезКонтекста предпочтительнее, когда данные самой формы не нужны: такой вызов не гоняет по сети всё содержимое формы и работает быстрее. Контекстный серверный вызов (&НаСервере) оправдан, только если серверному коду нужны реквизиты или таблицы формы.
Если нужно несколько реквизитов одного объекта, возвращайте их одним вызовом — структурой. Десять отдельных вызовов по одному реквизиту создадут десять обращений к серверу и заметно замедлят форму, особенно на веб-клиенте.
&НаСервереБезКонтекста
Функция РеквизитыКонтрагента(Ссылка)
Запрос = Новый Запрос(
"ВЫБРАТЬ Контрагенты.ИНН, Контрагенты.КПП
|ИЗ Справочник.Контрагенты КАК Контрагенты
|ГДЕ Контрагенты.Ссылка = &Ссылка");
Запрос.УстановитьПараметр("Ссылка", Ссылка);
Выборка = Запрос.Выполнить().Выбрать();
Результат = Новый Структура("ИНН, КПП", "", "");
Если Выборка.Следующий() Тогда
ЗаполнитьЗначенияСвойств(Результат, Выборка);
КонецЕсли;
Возврат Результат;
КонецФункции
Как передать значение с сервера на клиент и обратно
Обмен данными между директивами происходит через параметры и возвращаемые значения процедур и функций. Клиентская процедура вызывает серверную функцию, передавая примитивные типы, ссылки, структуры и массивы — всё это сериализуется платформой автоматически.
Ограничения: нельзя передавать на клиент объекты типа СправочникОбъект, Запрос, РезультатЗапроса и другие серверные сущности. Для передачи таблиц используют Массив структур или ТаблицаЗначений, помещённая в реквизит формы, либо ДанныеФормыКоллекция.
Обратное направление — с клиента на сервер — работает так же: клиентская процедура собирает значения реквизитов формы и передаёт их параметрами в серверную процедуру, которая выполняет запись или расчёт.
Способы получить значение
Мгновенно и без нагрузки, но только для реквизитов, добавленных в форму
Доступны данные формы на сервере, но передаётся весь контекст — медленнее
Быстрый и лёгкий, подходит для чтения реквизитов по ссылке, но данные формы недоступны
Значение всегда на клиенте без вызовов, но увеличивает объём передаваемых данных
Частые ошибки и как их исправить
Ошибка «Поле объекта не обнаружено» почти всегда означает, что реквизита нет в данных формы либо опечатка в имени. Откройте редактор формы и сверьте имя с деревом реквизитов.
Ошибка «Процедура или функция с указанным именем не определена» при серверном вызове возникает, когда функция объявлена с директивой &НаКлиенте, а вызывается из серверного контекста, или наоборот. Проверьте директивы компиляции.
Отдельная группа проблем — попытка выполнить запрос на клиенте: конструктор Новый Запрос недоступен в клиентском коде управляемого приложения. Запросы выполняются только на сервере, а на клиент возвращается готовый результат.
Как проверить, что значение получено правильно
Самый быстрый способ — отладчик: поставьте точку останова в клиентской процедуре и посмотрите значение переменной в табло. Для тонкого клиента отладка включается в настройках конфигуратора и параметре запуска.
Для оперативной проверки без отладчика используйте Сообщить() или ПоказатьПредупреждение() с выводом значения. Учитывайте, что ссылочные значения на клиенте выводятся представлением, поэтому для проверки типа используйте ТипЗнч() — он работает и на клиенте.
Как проверить результат
Содержит ожидаемое значение нужного типа
Неопределено или пустая ссылка
Совпадает с ожидаемым (СправочникСсылка, Число и т.д.)
Неопределено — значит, данные не были получены
Один серверный вызов на действие пользователя
Форма «подвисает» — вероятны вызовы в цикле
FAQ
Можно ли выполнить запрос к базе прямо на клиенте?
Нет. В управляемом приложении объект «Запрос» доступен только на сервере. Клиент вызывает серверную функцию, которая выполняет запрос и возвращает результат в виде структуры, массива или таблицы значений.
Чем отличается &НаСервере от &НаСервереБезКонтекста?
Контекстный вызов передаёт на сервер все данные формы, поэтому в нём доступны реквизиты и таблицы формы, но вызов тяжелее. Вызов без контекста передаёт только параметры — он быстрее, но к данным формы обращаться нельзя.
Почему Объект.МойРеквизит выдаёт «Поле объекта не обнаружено»?
Реквизит не добавлен в данные формы. Откройте редактор формы, перейдите на вкладку реквизитов и проверьте состав. Если реквизита там нет, добавьте его или получайте значение серверным вызовом.
Как получить реквизиты сразу нескольких строк таблицы?
Соберите ссылки из строк в массив на клиенте, передайте его одним серверным вызовом, на сервере выполните запрос с условием «Ссылка В (&МассивСсылок)» и верните результат. Это исключает множественные обращения к серверу.
Можно ли изменить реквизит объекта на клиенте?
Да, если реквизит присутствует в данных формы: присваивание вида Объект.Комментарий = "Текст" работает на клиенте, а изменения попадут в базу при записи объекта. Менять реквизиты других объектов (по ссылке) на клиенте нельзя — только через серверную процедуру записи.
Что делать, если серверный вызов недоступен в обработчике ожидания?
Серверные вызовы из обработчиков ожидания разрешены, но их следует использовать осторожно из-за нагрузки. Если платформа или настройки запрещают вызов, перенесите логику в явное действие пользователя — нажатие кнопки или обработчик изменения поля.
Что важно запомнить
На клиенте доступны только данные формы: реквизиты читаются напрямую через Объект или по имени реквизита формы, строки таблиц — через ТекущиеДанные с проверкой на Неопределено. Значения по ссылке получают серверным вызовом, предпочтительно без контекста и одним вызовом для нескольких реквизитов.