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

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

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

Почему обращение через индекс в ПутьКДанным не работает?

Рассмотрим ситуацию, с которой столкнулся автор темы. Он попытался программно добавить поле в форму списка и указать путь к данным следующим образом: Список.Ссылка.Работы[0].Комментарий. На первый взгляд логика понятна: мы обращаемся к ссылке текущей строки, переходим к табличной части Работы, выбираем первую строку по индексу 0 и берем поле Комментарий.

Однако выясним причину, по которой этот код не будет работать. Динамический список в 1С — это не массив объектов в оперативной памяти, а механизм, который генерирует SQL-запрос к базе данных. Система компоновки данных (СКД), лежащая в основе списка, транслирует ваши инструкции в запросы к СУБД. В языке SQL не существует понятия «индекс строки табличной части» в том виде, в котором мы привыкли видеть его в объектной технике 1С. Табличная часть — это отдельная физическая таблица, связанная с основной таблицей документа по полю Ссылка. Чтобы получить данные из нее, необходимо выполнить полноценное соединение таблиц — для этого подойдёт вывод оплат и отгрузок в списках заказов.

Проанализируем три подхода к решению этой проблемы: от «костыльных» до профессиональных.

Способ 1: Изменение текста запроса динамического списка (Рекомендуемый)

Самый правильный и производительный метод — это модификация самого текста запроса, на котором строится список — поможет инструменты разработчика для работы с запросами. Вместо того чтобы пытаться «вытащить» данные через точку от ссылки, мы добавим нужное поле непосредственно в выборку основного запроса. Рассмотрим, как это сделать программно в процедуре ПриСозданииНаСервере.

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


Процедура УР_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
   
 // 1. Модифицируем текст запроса динамического списка
    // Добавляем левое соединение с подзапросом, который выбирает первую строку ТЧ
    ТекстЗапроса = Список.ТекстЗапроса;
    
    // Подготовим новый текст с использованием псевдонима ПерваяСтрокаКомментарий
    НовыйТекстЗапроса = 
    "ВЫБРАТЬ
    |    ОсновнаяТаблица.Ссылка КАК Ссылка,
    |    ОсновнаяТаблица.Номер КАК Номер,
    |    ОсновнаяТаблица.Дата КАК Дата,
    |    ТЧ_ПерваяСтрока.Комментарий КАК ПерваяСтрокаКомментарий
    |ИЗ
    |    Документ.НазваниеВашегоДокумента КАК ОсновнаяТаблица
    |        ЛЕВОЕ СОЕДИНЕНИЕ (
    |            ВЫБРАТЬ
    |                ТЧ.Ссылка КАК Ссылка,
    |                МИНИМУМ(ТЧ.НомерСтроки) КАК НомерСтроки
    |            ИЗ
    |                Документ.НазваниеВашегоДокумента.Работы КАК ТЧ
    |            ГРУППИРОВАТЬ ПО
    |                ТЧ.Ссылка
    |        ) КАК ТЧ_МинНомер НА ОсновнаяТаблица.Ссылка = ТЧ_МинНомер.Ссылка
    |        ЛЕВОЕ СОЕДИНЕНИЕ Документ.НазваниеВашегоДокумента.Работы КАК ТЧ_ПерваяСтрока 
    |            НА ТЧ_МинНомер.Ссылка = ТЧ_ПерваяСтрока.Ссылка 
    |            И ТЧ_МинНомер.НомерСтроки = ТЧ_ПерваяСтрока.НомерСтроки";
    
    Список.ТекстЗапроса = НовыйТекстЗапроса;
    
    // 2. Программно добавляем элемент формы
    НЭлемент = Элементы.Добавить("УР_Описание", Тип("ПолеФормы"), Элементы.Список);
    НЭлемент.Вид = ВидПоляФормы.ПолеВвода;   
    НЭлемент.ПутьКДанным = "Список.ПерваяСтрокаКомментарий"; // Ссылаемся на поле из запроса
    
КонецПроцедуры

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

Способ 2: Использование события ПриПолученииДанныхНаСервере

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

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

Алгоритм действий:

  1. Добавляем в динамический список «ненаполненную» колонку (без пути к данным).
  2. В событии ПриПолученииДанныхНаСервере собираем все ссылки документов, попавших в выборку.
  3. Одним запросом получаем нужные данные из табличных частей для всех этих ссылок.
  4. Заполняем соответствующие ячейки в коллекции Строки.

Рассмотрим пример кода для этого события:


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

Важно помнить: этот метод может замедлить работу интерфейса при быстрой прокрутке, так как код выполняется каждый раз при обновлении состава строк на экране.

Способ 3: Дублирование данных в реквизит документа (Метод автора)

Проанализируем решение, к которому в итоге пришел автор вопроса. Он добавил в расширении дополнительный реквизит документа (например, УР_ПервыйКомментарий), который заполняется в момент записи документа значением из табличной части. После этого в списке просто выводится этот реквизит.

Рассмотрим, как это реализовать:

  1. Создаем реквизит УР_ПервыйКомментарий (строка, неограниченная длина или нужной длины).
  2. В модуле объекта или через подписку на событие ПередЗаписью пишем код:

Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    Если Работы.Количество() > 0 Тогда
        УР_ПервыйКомментарий = Работы[0].Комментарий;
    Иначе
        УР_ПервыйКомментарий = "";
    КонецЕсли;
КонецПроцедуры

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

Подведем итоги

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

При программном создании элемента формы всегда убеждайтесь, что поле, указанное в НЭлемент.ПутьКДанным, действительно присутствует в колонках динамического списка. Иногда после добавления требуется выполнить программное перемещение колонки динамического списка, чтобы данные отображались в удобном для пользователя месте. Использование префикса Список. обязательно при программном добавлении элементов, связанных с данными динамического списка.

← На главную