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