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