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