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

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

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

Выясним причину: почему данные не отображаются на форме

В управляемом приложении клиентский объект формы представляет собой тип ДанныеФормыСтруктура, а не привычный прикладной объект ДокументОбъект. Когда на клиенте мы получаем значение реквизита через ВладелецФормы.Объект и передаем его на сервер, изменяется копируемая структура данных. Однако изменения не отражаются автоматически на самом интерфейсе формы, пока данные не будут явно скопированы обратно в реквизит формы или не будет выполнена обратная трансформация.

Способ 1. Использование процедуры КопироватьДанныеФормы

Рассмотрим по шагам первый подход. Мы передаем данные структуры на сервер, производим расчеты и загружаем результат в табличную часть объекта, после чего с помощью процедуры КопироватьДанныеФормы синхронизируем изменения с формой-владельцем.

Посмотрим на пример клиент-серверного взаимодействия:


&НаКлиенте
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ОбъектыНазначенияМассив) Экспорт
    
    ДокОбъект = ВладелецФормы.Объект;
    
    Если ДокОбъект.Склад.Пустая() Тогда
        Сообщить("Не выбран склад!");
    Иначе    
        ПолучитьОстаткиИнвентаряНаСервере(ДокОбъект);
        КопироватьДанныеФормы(ДокОбъект, ВладелецФормы.Объект);    
        ВладелецФормы.Модифицированность = Истина;
    КонецЕсли;

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

&НаСервере
Процедура ПолучитьОстаткиИнвентаряНаСервере(ДокОбъект)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   ХозрасчетныйОстатки.Счет КАК СчетУчета,
        |   ХозрасчетныйОстатки.Субконто1 КАК Номенклатура,
        |   ХозрасчетныйОстатки.КоличествоОстаток КАК Количество
        |ИЗ
        |   РегистрБухгалтерии.Хозрасчетный.Остатки(
        |       &Период,
        |       Счет = &Счет1009,
        |       ,
        |       Субконто2 = &Склад И Организация = &Организация) КАК ХозрасчетныйОстатки";
    
    Запрос.УстановитьПараметр("Организация", ДокОбъект.Организация);
    Запрос.УстановитьПараметр("Период", ДокОбъект.Дата);
    Запрос.УстановитьПараметр("Склад", ДокОбъект.Склад);
    Запрос.УстановитьПараметр("Счет1009", ПланыСчетов.Хозрасчетный.ИнвентарьИХозяйственныеПринадлежности);
    
    ТаблицаОстатков = Запрос.Выполнить().Выгрузить();
    ТаблицаОстатков.Колонки.Добавить("ФизЛицо");
    
    // Получаем ответственное лицо один раз до цикла для оптимизации
    МолоЛицо = ОтветственныеЛицаБП.ОтветственноеЛицоНаСкладе(ДокОбъект.Склад, ДокОбъект.Дата);
    Для Каждого Строка Из ТаблицаОстатков Цикл
        Строка.ФизЛицо = МолоЛицо;
    КонецЦикла;    
    
    ДокОбъект.ИнвентарьИХозяйственныеПринадлежности.Загрузить(ТаблицаОстатков);
    
КонецПроцедуры

Обратите внимание: Метод Загрузить() у табличной части заполняет данные только в том случае, если названия и типы колонок в загружаемой таблице значений полностью совпадают с именами реквизитов табличной части документа (например, СчетУчета, Номенклатура, Количество, ФизЛицо).

Способ 2. Преобразование реквизита формы в прикладной объект

Если логика заполнения выполняется непосредственно в контексте формы документа, наиболее лаконичным решением является использование пары системных функций РеквизитФормыВЗначение и ЗначениеВРеквизитФормы.

Проанализируем этот алгоритм:

  1. Преобразуем реквизит формы Объект (имеющий тип ДанныеФормыСтруктура) в полноценный прикладной объект ДокументОбъект.
  2. Загружаем выгрузку запроса или таблицы значений в табличную часть документа.
  3. Возвращаем измененный объект обратно в реквизит формы.

Рассмотрим пример кода на сервере:


&НаСервере
Процедура ЗаполнитьТабличнуюЧастьНаСервере()

    // 1. Конвертируем реквизит формы в объект документа
    ДокументОбъект = РеквизитФормыВЗначение("Объект");
    
    // 2. Выполняем запрос и загружаем результат в ТЧ
    РезультатЗапроса = ВыполнитьЗапросПоОстаткам(ДокументОбъект);
    ДокументОбъект.ИнвентарьИХозяйственныеПринадлежности.Загрузить(РезультатЗапроса.Выгрузить());
    
    // 3. Возвращаем обновленный объект в контекст формы
    ЗначениеВРеквизитФормы(ДокументОбъект, "Объект");

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

Важные рекомендации по оптимизации

При написании кода заполнения табличных частей рекомендуем учитывать следующие правила производительности и архитектуры 1С:

  1. Вызов функций внутри циклов: Никогда не вызывайте тяжелые функции обращения к базе данных (такие как получение ответственных лиц) внутри цикла перебора строк. Вычисляйте значение один раз до начала цикла и присваивайте его элементам.
  2. Группировка в запросах к виртуальным таблицам: Таблица Остатки регистра бухгалтерии уже возвращает сгруппированные итоговые данные. Повторное использование СУММА() и СГРУППИРОВАТЬ ПО поверх виртуальной таблицы создает лишнюю нагрузку на СУБД.
  3. Установка флага модифицированности: При изменении реквизитов формы вручную с клиента обязательно устанавливайте ВладелецФормы.Модифицированность = Истина, чтобы платформа предложила пользователю сохранить документ при закрытии.
← На главную