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