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