Как программно изменить тип реквизита формы на составной в 1С

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

В практике разработки на платформе 1С:Предприятие часто возникает задача создания гибких интерфейсов. Один из типичных сценариев: пользователь выбирает поле (например, из списка доступных реквизитов документа), и следующее поле ввода должно автоматически подстроиться под выбранный тип данных. Если выбран «Контрагент» — поле должно стать ссылкой на справочник контрагентов, если «Сумма» — числом, а если «Объект расчета» — поле должно поддерживать составной тип данных (например, ссылки на договоры и документы расчетов).

Многие начинающие разработчики совершают одну и ту же ошибку, пытаясь использовать метод ПривестиЗначение для изменения поведения реквизита. Разберем подробно, почему это не работает и как реализовать задачу правильно.

Разбор ошибки: почему ПривестиЗначение не меняет тип реквизита

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

Метод ОписаниеТипов.ПривестиЗначение() предназначен для того, чтобы взять конкретное данное (например, строку "123") и попытаться преобразовать его в тип, описанный в объекте ОписаниеТипов (например, в число 123). Однако сам реквизит, в который вы записываете результат, остается тем же самым типом, который был задан ему при создании в конфигураторе.

Если ваш Реквизит1 в метаданных определен как Строка, то что бы вы туда ни записывали, платформа всегда будет пытаться преобразовать это в строку. Если вы запишете туда ссылку, 1С просто сохранит строковое представление этой ссылки (наименование объекта). Чтобы поле на форме начало вести себя как ссылка (появилась кнопка выбора, открывался список справочника), нужно изменить описание типа самого реквизита формы, а не просто преобразовать значение. Для решения подобных задач отлично подойдёт пример динамического добавления и удаления элементов управляемой формы.

Способ 1. Программное изменение реквизитов формы

Для того чтобы изменить тип уже существующего реквизита на управляемой форме, необходимо использовать механизм динамического изменения состава реквизитов. В 1С это реализуется через метод ИзменитьРеквизиты(). Проанализируем алгоритм действий:

  1. Удаление старого реквизита: Мы не можем просто «перенастроить» тип у существующего реквизита. Нам нужно удалить старый и добавить новый с тем же именем, но другим типом.
  2. Создание нового описания типа: Нам нужно получить объект ОписаниеТипов от эталонного реквизита.
  3. Применение изменений: Вызов метода ИзменитьРеквизиты().
  4. Обновление элемента формы: Поскольку реквизит был пересоздан, нам нужно заново связать его с элементом управления (полем ввода) на форме.

Рассмотрим пример кода, который реализует этот подход. Предположим, у нас есть Реквизит1, тип которого мы хотим менять динамически, основываясь на типе Реквизит2:


// Получаем описание типов от реквизита-донора
ОписаниеТипаДонора = ТипЗнч(Объект.Реквизит2); 
// Или, если нужно получить описание типов как объект:
ОписаниеТипаДонора = Элементы.Реквизит2.ОграничениеТипа;

// Массивы для добавления и удаления
МассивДобавляемыхРеквизитов = Новый Массив;
МассивУдаляемыхРеквизитов = Новый Массив;

// Добавляем имя старого реквизита в массив на удаление
МассивУдаляемыхРеквизитов.Добавить("Реквизит1");

// Описываем новый реквизит с тем же именем, но новым типом
НовыйРеквизит = Новый РеквизитФормы("Реквизит1", ОписаниеТипаДонора, , "Заголовок поля", Истина);
МассивДобавляемыхРеквизитов.Добавить(НовыйРеквизит);

// Выполняем операцию на сервере
ЭтаФорма.ИзменитьРеквизиты(МассивДобавляемыхРеквизитов, МассивУдаляемыхРеквизитов);

// Важно: перепривязываем путь к данным для элемента формы
Элементы.Реквизит1.ПутьКДанным = "Реквизит1";

Важный нюанс: Этот метод работает только на сервере. При изменении реквизитов формы все данные, которые были введены в старый реквизит, будут потеряны, так как объект создается заново. Чтобы упростить этот процесс, можно использовать общий модуль для программного изменения управляемых форм.

Способ 2. Использование типа Произвольный и ОграничениеТипа

Если мы заранее не знаем, какие типы могут потребоваться, или не хотим постоянно пересоздавать реквизиты (что является довольно «тяжелой» операцией для системы), можно пойти другим путем. Рассмотрим использование типа Произвольный.

Если у реквизита формы в конфигураторе установлен тип Произвольный (или в составном типе выбраны все возможные ссылки), мы можем управлять поведением поля ввода через свойство элемента формы ОграничениеТипа.

Выясним, как это работает по шагам:

  1. Устанавливаем для Реквизит1 максимально широкий тип (например, Произвольный).
  2. В момент, когда пользователь выбирает «ведущий» реквизит, мы получаем его тип.
  3. Устанавливаем этот тип в свойство ОграничениеТипа элемента формы, связанного с Реквизит1.

&НаКлиенте
Процедура ПриИзмененииВедущегоРеквизита(Элемент)
    
    // Получаем описание типов из метаданных или другого элемента
    НовоеОписаниеТипов = ПолучитьОписаниеТиповДляРеквизита(); 
    
    // Ограничиваем выбор в поле ввода
    ЭлементФормыРеквизит1 = Элементы.Реквизит1;
    ЭлементФормыРеквизит1.ОграничениеТипа = НовоеОписаниеТипов;
    
    // Если текущее значение не входит в новый тип - очищаем его
    Объект.Реквизит1 = НовоеОписаниеТипов.ПривестиЗначение(Объект.Реквизит1);
    
КонецПроцедуры

Этот способ гораздо производительнее, так как не требует серверного вызова ИзменитьРеквизиты и перерисовки всей формы. Поле ввода автоматически подстроит кнопку выбора: если в ОграничениеТипа один тип — сразу откроется нужный справочник, если несколько (составной тип) — сначала появится меню выбора типа.

Работа с Планами видов характеристик (ПВХ)

В тексте обращения упоминалось, что Реквизит2 является ссылкой на План видов характеристик. Это особый случай. У объектов ПВХ есть свойство ТипЗначения, которое само по себе является объектом ОписаниеТипов.

Проанализируем ситуацию: если ваш реквизит должен принимать тип, соответствующий выбранной характеристике, вам нужно вытащить это описание из самой характеристики:


&НаСервере
Функция ПолучитьОписаниеТипаИзХарактеристики(ВыбраннаяХарактеристика)
    Возврат ВыбраннаяХарактеристика.ТипЗначения;
КонецФункции

Затем это описание типов можно использовать либо в первом, либо во втором способе, описанных выше. Помните, что составной тип в ПВХ может быть очень объемным, и правильное ограничение типа — залог того, что пользователь не запутается при выборе значения.

Резюме и рекомендации

Подведем итог нашему исследованию:

Использование этих подходов позволит вам создавать профессиональные и отзывчивые интерфейсы, которые корректно работают с любыми типами данных, включая сложные составные типы и планы видов характеристик.

← На главную