Почему возникает ошибка «Значение не является значением объектного типа» при расчете строк табличной части и как её исправить?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке управляемых форм в платформе 1С:Предприятие 8.3 разработчики часто сталкиваются с ошибкой «Значение не является значением объектного типа» при попытке вычислить итоги или пересчитать значения в колонках табличной части документа. Разберем по шагам, почему возникает эта ошибка и как правильно организовать алгоритм пересчета данных.

Анализ причин возникновения ошибки

Проанализируем типовую ситуацию: в коде клиентской процедуры выполняется попытка получить текущую строку таблицы формы через свойство Элементы.ИмяТаблицы.ТекущиеДанные:


&НаКлиенте
Процедура ИтогоНачисления()
    СтрокаТЧ = Элементы.Начисление.ТекущиеДанные;
    СтрокаТЧ.КВыплате = СтрокаТЧ.Сумма + СтрокаТЧ.КомпенсацияСвязи - СтрокаТЧ.ОтчисленияПоБольничным;
КонецПроцедуры

В момент выполнения строки присвоения система аварийно завершает работу с исключением, указывая на то, что поле не найдено в объекте. Выясним причину такого поведения:

  1. Свойство ТекущиеДанные содержит Неопределено. Если табличная часть была только что заполнена программно на сервере, визуальный элемент таблицы на клиенте еще не получил фокус и не имеет активной строки. В этом случае переменная СтрокаТЧ принимает значение Неопределено. Любая попытка обратиться к свойству через точку (например, СтрокаТЧ.КВыплате) приводит к ошибке объектного типа.
  2. Ошибочная логика обхода в цикле. При попытке пересчитать всю таблицу разработчик нередко запускает цикл по коллекции данных Для каждого Стр Из Объект.Начисление Цикл, но внутри вызывает процедуру, обращающуюся к Элементы.Начисление.ТекущиеДанные. Сам по себе цикл по коллекции объекта не изменяет текущую активную строку в визуальном элементе формы.
  3. Синтаксические ошибки при вызове методов. Пропуск круглых скобок при вызове методов (например, Запрос.Выполнить.Выгрузить вместо Запрос.Выполнить().Выгрузить() или Объект.Начисление.Добавить вместо Объект.Начисление.Добавить()) приводит к некорректному заполнению данных.
  4. Наличие значений NULL после запроса. Если данные заполняются левым соединением из регистров сведений, пустые значения возвращаются как NULL. Математические операции с NULL дают непредвиденные результаты при дальнейшей обработке.

Способ 1. Универсальная процедура расчета строки с передачей контекста

Рассмотрим правильный подход к организации вычислений на клиенте. Создадим отдельную процедуру пересчета, которая принимает конкретную строку табличной части как параметр. Это позволит использовать один и тот же алгоритм как для пересчета активной строки при интерактивном вводе, так и для пакетной обработки всех строк таблицы.

Посмотрим на пример реализации:


&НаКлиенте
Процедура РассчитатьСтроку(СтрокаТЧ)
    
    // Обязательно проверяем, передана ли строка
    Если СтрокаТЧ = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    СтрокаТЧ.КВыплате = СтрокаТЧ.Сумма 
        + СтрокаТЧ.КомпенсацияСвязи 
        + СтрокаТЧ.КомпенсацияМолока 
        + СтрокаТЧ.ДоплатаЗаНочныеЧасы 
        + СтрокаТЧ.ДоплатаЗаПереработку 
        + СтрокаТЧ.КомпенсацияОтпуска 
        + СтрокаТЧ.ДоплатыЗаУборку 
        - СтрокаТЧ.ОтчисленияЗаЧБОП 
        - СтрокаТЧ.ОтчисленияПоБольничным;

КонецПроцедуры

Теперь эту процедуру можно безопасно вызывать в различных сценариях:

  1. При интерактивном изменении ячейки пользователем (в событии ПриИзменении поля ввода):
    
    &НаКлиенте
    Процедура НачислениеСуммаПриИзменении(Элемент)
        СтрокаТЧ = Элементы.Начисление.ТекущиеДанные;
        РассчитатьСтроку(СтрокаТЧ);
    КонецПроцедуры
    
  2. При циклическом пересчете всех строк документа на клиенте:
    
    &НаКлиенте
    Процедура ПересчитатьВсеСтроки()
        Для Каждого Стр Из Объект.Начисление Цикл
            РассчитатьСтроку(Стр);
        КонецЦикла;
    КонецПроцедуры
    

Способ 2. Выполнение расчетов на сервере и обработка в запросе

Если табличная часть заполняется программно по кнопке (например, остатками или ставками из регистров), наиболее эффективным решением является выполнение всех математических расчетов непосредственно на сервере без лишних клиентских вызовов.

Разберем пример серверного заполнения и расчета с корректной обработкой возможных значений NULL:


&НаСервере
Процедура ЗаполнитьИРассчитатьНаСервере()
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	СписокСотрудников.Ссылка КАК ФИО,
        |	ЕСТЬNULL(СтавкиЗП.Сумма, 0) КАК Сумма,
        |	ЕСТЬNULL(СтавкиЗП.КомпенсацияСвязи, 0) КАК КомпенсацияСвязи,
        |	ЕСТЬNULL(СтавкиЗП.КомпенсацияМолока, 0) КАК КомпенсацияМолока
        |ИЗ
        |	Справочник.СписокСотрудников КАК СписокСотрудников
        |	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СтавкиЗП.СрезПоследних(&Период, ) КАК СтавкиЗП
        |		ПО СписокСотрудников.Ссылка = СтавкиЗП.ФИО
        |ГДЕ
        |	СписокСотрудников.Статус = &Статус";
        
    Запрос.УстановитьПараметр("Период", Объект.Дата);
    Запрос.УстановитьПараметр("Статус", ПредопределенноеЗначение("Перечисление.РаботаетУволен.Работает"));
    
    Выборка = Запрос.Выполнить().Выбрать();
    
    Объект.Начисление.Очистить();
    
    Пока Выборка.Следующий() Цикл
        НоваяСтрока = Объект.Начисление.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка);
        
        // Первичный расчет прямо в серверном цикле
        НоваяСтрока.КВыплате = НоваяСтрока.Сумма 
            + НоваяСтрока.КомпенсацияСвязи 
            + НоваяСтрока.КомпенсацияМолока;
    КонецЦикла;
    
КонецПроцедуры

Способ 3. Программная установка активной строки

Если после заполнения таблицы интерфейс требует позиционирования курсора на первой строке, установим текущую строку программно через передачу её идентификатора:


&НаКлиенте
Процедура ПослеЗаполненияТаблицы()
    Если Объект.Начисление.Количество() > 0 Тогда
        Элементы.Начисление.ТекущаяСтрока = Объект.Начисление[0].ПолучитьИдентификатор();
    КонецЕсли;
КонецПроцедуры

Таким образом, разделение логики работы со строками данных (коллекция Объект.ИмяТЧ) и элементов визуального отображения (Элементы.ИмяТЧ) полностью исключает ошибку «Значение не является значением объектного типа».

← На главную