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