Как получить все реквизиты документа и динамически вывести их на форму в 1С 8.3?

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

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

Шаг 1. Получение списка реквизитов через метаданные и чтение их значений

Для того чтобы обойти структуру любого документа, переданного в качестве ссылки, воспользуемся объектом метаданных. Метод Метаданные() позволяет получить описание конфигурации для конкретного объекта данных.

Рассмотрим серверную процедуру обхода реквизитов документа. Обратите внимание, что обращение к значению реквизита по его имени выполняется через оператор индексации Док[Реквизит.Имя]:


&НаСервере
Процедура ОбойтиРеквизитыДокумента(ДокСсылка)

    Если Не ЗначениеЗаполнено(ДокСсылка) Тогда
        Возврат;
    КонецЕсли;

    МетаданныеДокумента = ДокСсылка.Метаданные();

    // Обход пользовательских реквизитов
    Для Каждого ОписаниеРеквизита Из МетаданныеДокумента.Реквизиты Цикл
        ИмяРеквизита = ОписаниеРеквизита.Имя;
        ЗначениеРеквизита = ДокСсылка[ИмяРеквизита];
        
        Сообщить(СтрШаблон("Реквизит: %1, Значение: %2", ИмяРеквизита, ЗначениеРеквизита));
    КонецЦикла;

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

Важное замечание: коллекция Метаданные().Реквизиты содержит только дополнительные реквизиты, созданные разработчиком. Общесистемные поля, такие как Номер, Дата, Проведен или ПометкаУдаления, хранятся в отдельной коллекции МетаданныеДокумента.СтандартныеРеквизиты. Если требуется полный список реквизитов, необходимо дополнительно обойти и эту коллекцию.

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

Шаг 2. Программное создание реквизитов и элементов формы

Когда коллекция реквизитов получена, требуется вывести их на управляемую форму. В управляемом интерфейсе 1С данные формы отделены от интерфейсных элементов. Процесс создания полей состоит из двух связанных действий:

  1. Создание реквизитов формы через конструктор Новый РеквизитФормы() и применение изменений методом ИзменитьРеквизиты().
  2. Создание элементов интерфейса через коллекцию ЭтаФорма.Элементы.Добавить() и привязка их свойства ПутьКДанным к созданным реквизитам.

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


&НаСервере
Процедура СоздатьДинамическиеПоля(МассивНовыхРеквизитов, СтруктураЗначений)

    // Применяем добавление реквизитов в структуру формы
    ЭтаФорма.ИзменитьРеквизиты(МассивНовыхРеквизитов);

    Счетчик = 0;
    Для Каждого РеквизитФормы Из МассивНовыхРеквизитов Цикл
        Счетчик = Счетчик + 1;
        ИмяЭлемента = "ПолеДинамическое_" + РеквизитФормы.Имя + "_" + Счетчик;
        
        // Создаем поле ввода в корне формы или в предназначенной группе
        Элемент = ЭтаФорма.Элементы.Добавить(ИмяЭлемента, Тип("ПолеФормы"), ЭтаФорма);
        Элемент.Вид = ВидПоляФормы.ПолеВвода;
        Элемент.ПутьКДанным = РеквизитФормы.Имя;
        
        // Заполняем значение реквизита на форме
        ЭтаФорма[РеквизитФормы.Имя] = СтруктураЗначений[РеквизитФормы.Имя];
    КонецЦикла;

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

Шаг 3. Корректная очистка и пересоздание реквизитов при смене документа

Выясним причину частой ошибки: при повторном выборе документа и попытке удалить старые реквизиты разработчики сталкиваются с ошибкой «Не может найти путь к данным». Это происходит из-за нарушения порядка очистки объектов:

  1. Ошибочный порядок: попытка удалить реквизит данных формы до того, как удален или отвязан связанный с ним элемент интерфейса. Элемент формы не может существовать с недействительным свойством ПутьКДанным.
  2. Неверный тип параметров метода ИзменитьРеквизиты(): первый параметр принимает массив объектов РеквизитФормы (добавляемые данные), а второй параметр должен содержать исключительно массив строк с именами реквизитов (удаляемые данные). Попытка передать во второй параметр объекты или ссылки вызовет аварийное завершение.
  3. Удаление только динамических данных: удалять через ИзменитьРеквизиты() разрешено исключительно те реквизиты, которые были созданы программно в текущем сеансе работы формы.

Проанализируем правильный алгоритм пересоздания полей на форме:


&НаСервере
Процедура ОчиститьДинамическиеЭлементыИРеквизиты()

    // 1. Сначала удаляем элементы интерфейса
    МассивДляУдаленияРеквизитов = Новый Массив;
    
    // Имена созданных реквизитов рекомендуется сохранять, например, в реквизите формы "СписокСозданныхРеквизитов"
    Для Каждого ИмяРеквизита Из СписокСозданныхРеквизитов Цикл
        
        // Находим и удаляем элемент формы
        ИмяЭлемента = "ПолеДинамическое_" + ИмяРеквизита;
        ЭлементФормы = ЭтаФорма.Элементы.Найти(ИмяЭлемента);
        Если ЭлементФормы <> Неопределено Тогда
            ЭтаФорма.Элементы.Удалить(ЭлементФормы);
        КонецЕсли;
        
        // Добавляем строковое имя для удаления из структуры данных
        МассивДляУдаленияРеквизитов.Добавить(ИмяРеквизита);
        
    КонецЦикла;

    // 2. Удаляем сами реквизиты формы (передаем пустой массив добавляемых и массив имен удаляемых)
    Если МассивДляУдаленияРеквизитов.Количество() > 0 Тогда
        ЭтаФорма.ИзменитьРеквизиты(Новый Массив, МассивДляУдаленияРеквизитов);
        СписокСозданныхРеквизитов.Очистить();
    КонецЕсли;

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

Альтернативное решение: использование статической таблицы значений

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

В большинстве прикладных задач намного проще и надежнее не перестраивать элементы управления, а вывести на форму стандартный элемент Таблица, связанный с реквизитом формы типа ТаблицаЗначений. В таблице создаются фиксированные колонки: «Имя реквизита», «Синоним» и «Значение». При изменении документа таблица просто очищается и повторно заполняется за один проход метаданных, исключая любые ошибки динамических путей к данным.

← На главную