Как вывести данные из табличной части в форму списка 1С

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

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

Суть проблемы и выбор стратегии

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

Для решения этой задачи мы проанализируем три основных метода:

  1. Создание вспомогательного реквизита в шапке документа (самый надежный и быстрый способ).
  2. Использование обработчика «ПриПолученииДанныхНаСервере» в динамическом списке (без изменения структуры базы).
  3. Использование механизмов БСП (для типовых конфигураций).

Решение 1: Создание вспомогательного реквизита «СотрудникиСтрокой»

Этот метод считается «золотым стандартом» в 1С. Мы создаем в объекте специальное поле, в которое при записи документа будем сохранять список сотрудников в виде одной длинной строки.

Шаг 1: Добавление реквизита

Разберем по шагам: откроем конфигуратор, найдем наш документ и добавим новый реквизит в Шапку. Назовем его СотрудникиСтрокой. Тип данных выберем Строка, длину укажем достаточную (например, 200 или 500 символов, либо неограниченную, если сотрудников может быть очень много).

Шаг 2: Написание кода в модуле объекта

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

Рассмотрим пример кода с использованием обычного цикла:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Инициализируем пустую строку
    СписокСотрудников = "";
    
    // Обходим табличную часть циклом
    Для Каждого СтрокаТЧ Из Сотрудники Цикл
        
        // Получаем представление сотрудника (ссылку преобразуем в строку)
        ИмяСотрудника = Строка(СтрокаТЧ.Сотрудник);
        
        // Добавляем к общей строке через запятую
        Если ЗначениеЗаполнено(СписокСотрудников) Тогда
            СписокСотрудников = СписокСотрудников + ", " + ИмяСотрудника;
        Иначе
            СписокСотрудников = ИмяСотрудника;
        КонецЕсли;
        
    КонецЦикла;
    
    // Записываем результат в наш реквизит шапки
    СотрудникиСтрокой = СписокСотрудников;

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

Шаг 3: Оптимизация с помощью СтрСоединить

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


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)

    // Выгружаем колонку 'Сотрудник' из ТЧ в массив
    МассивСотрудников = Сотрудники.ВыгрузитьКолонку("Сотрудник");
    
    // Преобразуем массив ссылок в массив строк (представлений)
    Для Сч = 0 По МассивСотрудников.Количество() - 1 Цикл
        МассивСотрудников[Сч] = Строка(МассивСотрудников[Сч]);
    КонецЦикла;
    
    // Соединяем все элементы массива в одну строку через запятую
    СотрудникиСтрокой = СтрСоединить(МассивСотрудников, ", ");

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

Решение 2: Динамическое формирование в списке (ПриПолученииДанныхНаСервере)

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

Особенности этого метода:

Разберем пример реализации. В форме списка создаем обработчик:


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

Решение 3: Использование типовых функций БСП

Если ваша конфигурация построена на базе Библиотеки Стандартных Подсистем (БСП), проанализируем возможности общих модулей. В типовых решениях, таких как ЗУП или ERP, часто уже есть готовые механизмы для формирования краткого состава документа.

Посмотрим на пример использования функции из БСП:


// В модуле объекта
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    ПараметрыСостава = ОбщегоНазначения.СформироватьСписокСотрудников(Сотрудники);
    СотрудникиСтрокой = ПараметрыСостава.Текст;
    
КонецПроцедуры

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

Важные нюансы и оптимизация интерфейса

Проанализируем ситуацию с точки зрения удобства пользователя. Если в документе 50 сотрудников, строка в списке станет огромной и не поместится на экран. Как сделать лучше?

1. Ограничение длины строки

При заполнении реквизита в ПередЗаписью можно ограничивать результат. Например, выводить только первых трех сотрудников, а далее писать «и другие».

2. Использование подсказок (ToolTip)

Хорошим тоном считается вывод полной строки сотрудников в свойство ячейки Подсказка. Настроим форму списка так: основная колонка показывает начало списка, а при наведении курсора пользователь видит весь состав в сплывающем окне.

3. Актуализация данных

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

Резюме

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

← На главную