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

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

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

Почему возникает ошибка при прямом обращении к реквизитам другой формы?

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

Правильный алгоритм действий выглядит так:

  1. Во второй форме пользователь вводит только новые данные. После этого форма возвращает эти данные (например, в виде структуры) обратно в первую форму.
  2. Первая форма «ловит» эти данные и сохраняет их в промежуточном хранилище — специальном реквизите формы с типом ТаблицаЗначений. Это позволяет накапливать строки с информацией.
  3. Первая форма очищает свой табличный документ и формирует его заново на основании всех накопленных данных из таблицы значений, попутно подсчитывая итоги.

Разберем по шагам реализацию этого механизма.

Шаг 1. Передача данных со второй (подчиненной) формы

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

Посмотрим на пример. Предположим, у нас есть поля ввода ФИО, Должность и Оклад. При нажатии на кнопку «Добавить» на второй форме, мы сформируем структуру и передадим ее с помощью метода Закрыть():


&НаКлиенте
Процедура КомандаДобавитьСотрудника(Команда)
    
    ДанныеСотрудника = Новый Структура;
    ДанныеСотрудника.Вставить("ФИО", ФИО);
    ДанныеСотрудника.Вставить("Должность", Должность);
    ДанныеСотрудника.Вставить("Оклад", Оклад);
    
    // Закрываем текущую форму и передаем структуру в форму-владелец
    ЭтаФорма.Закрыть(ДанныеСотрудника);
    
КонецПроцедуры

Если же бизнес-процесс требует вводить несколько сотрудников подряд без закрытия формы, вместо метода Закрыть() следует использовать глобальное оповещение с помощью метода Оповестить():


&НаКлиенте
Процедура КомандаДобавитьСотрудника(Команда)
    // ... создание структуры ...
    Оповестить("ДобавленНовыйСотрудник", ДанныеСотрудника);
КонецПроцедуры

Шаг 2. Прием данных на основной форме и накопление в Таблице Значений

Теперь перейдем в модуль первой (главной) формы. Нам нужно создать реквизит формы с типом ТаблицаЗначений (назовем его, например, ТаблицаСотрудников), в котором будут колонки: ФИО, Должность, Оклад.

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


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

Если мы использовали Оповестить(), то данные принимаются в обработчике ОбработкаОповещения, код внутри будет аналогичным.

Шаг 3. Подсчет итогов и формирование Табличного Документа

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

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


&НаСервере
Процедура ОбновитьТабличныйДокументНаСервере()
    
    // Получаем реквизит формы типа ТабличныйДокумент
    ТабДок = ЭтаФорма.СотрудникиТабДок; 
    
    // Обязательно очищаем перед новым заполнением!
    ТабДок.Очистить();
    
    // Получаем макет из объекта обработки/отчета
    Макет = РеквизитФормыВЗначение("Объект").ПолучитьМакет("Макет");
    
    ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
    ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
    ОбластьПодвал = Макет.ПолучитьОбласть("Подвал");
    
    // 1. Выводим шапку
    ТабДок.Вывести(ОбластьШапка);
    
    // 2. Выводим строки в цикле по нашей накопленной Таблице Значений
    Для Каждого СтрокаТЗ Из ЭтаФорма.ТаблицаСотрудников Цикл
        ОбластьСтрока.Параметры.Заполнить(СтрокаТЗ);
        ТабДок.Вывести(ОбластьСтрока);
    КонецЦикла;
    
    // 3. Считаем итоги и выводим подвал
    ИтоговыйОклад = ЭтаФорма.ТаблицаСотрудников.Итог("Оклад");
    
    // Передаем подсчитанный итог в параметр подвала
    ОбластьПодвал.Параметры.ИтогоОклад = ИтоговыйОклад; 
    ТабДок.Вывести(ОбластьПодвал);
    
КонецПроцедуры

Подведем итоги совместной работы

Мы проанализировали правильную цепочку взаимодействия управляемых форм. Запомните ключевые правила:

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

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

← На главную