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