При разработке интерфейсов на обычных формах в 1С довольно часто возникает задача организации сложных иерархических структур данных. Например, когда для каждой строки родительской таблицы (например, «Готовая продукция») требуется хранить подчиненный список элементов (например, «Комплект» или спецификацию). Рассмотрим, почему стандартное присвоение одной таблицы значений в ячейку другой может не работать и как правильно реализовать эту логику.
Разберем типичную ошибку при работе с табличными полями. Попытка записать данные подчиненного поля непосредственно через элементы формы, например ЭлементыФормы.ГотоваяПродукция.ТекущаяСтрока.ТЗ = Комплект, приводит к непредсказуемому behavior или получению пустого значения при обновлении подчиненной таблицы.
Выясним причину такого поведения:
ТабличноеПоле — это лишь визуальное «окно» для отображения информации. Непосредственная работа с данными должна происходить с объектом-источником — ТаблицаЗначений.Стр.ТЗ = Комплект в ячейку помещается ссылка на тот же самый объект таблицы в памяти. Когда подчиненная таблица Комплект очищается или перезаполняется (например, через метод Очистить()), данные сбрасываются и внутри ячейки родительской таблицы.Чтобы подчиненные данные корректно сохранялись для каждой строки родительской таблицы и не терялись при обновлении, разберем пошаговый алгоритм решения.
Шаг 1. Инициализация колонки источника данных
В процедуре инициализации формы (например, ПриОткрытии) необходимо добавить колонку в сам объект-источник ТаблицаЗначений, а затем пересоздать колонки визуального элемента ТабличноеПоле. Желательно явно задавать тип хранимых данных с помощью ОписаниеТипов:
Процедура ПриОткрытии()
// Добавляем колонку для хранения вложенной таблицы значений
ГотоваяПродукция.Колонки.Добавить("ТЗ", Новый ОписаниеТипов("ТаблицаЗначений"));
// Обновляем отображение колонок на форме
ЭлементыФормы.ГотоваяПродукция.СоздатьКолонки();
КонецПроцедуры
Шаг 2. Копирование подчиненной таблицы в ячейку строки
Для создания независимого экземпляра данных при сохранении подчиненного списка в ячейку необходимо использовать метод Скопировать(). Это разрывает ссылку на исходный объект Комплект и создает отдельную копию таблицы значений в памяти.
Посмотрим на пример функции сохранения:
Функция СохранимТЗДляГотовойПрод()
Если ГотоваяПродукция.Количество() > 0 Тогда
// Получаем индекс текущей выбранной строки
ТекущиеДанные = ЭлементыФормы.ГотоваяПродукция.ТекущиеДанные;
Если ТекущиеДанные <> Неопределено Тогда
ИндексТекСтроки = ГотоваяПродукция.Индекс(ТекущиеДанные);
Стр = ГотоваяПродукция[ИндексТекСтроки];
// Сохраняем копию таблицы значений в ячейку
Стр.ТЗ = Комплект.Скопировать();
КонецЕсли;
КонецЕсли;
КонецФункции
Шаг 3. Считывание данных при активизации строки
При переходе пользователя по строкам родительской таблицы необходимо считывать сохраненную таблицу значений из ячейки и загружать ее в подчиненное табличное поле:
Процедура ГотоваяПродукцияПриАктивизацииСтроки(Элемент)
ЗаполнимКомплектЗначениямиСпецификации();
КонецПроцедуры
Функция ЗаполнимКомплектЗначениямиСпецификации()
ТекущиеДанные = ЭлементыФормы.ГотоваяПродукция.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
ВложеннаяТЗ = ТекущиеДанные.ТЗ;
// Проверяем, инициализирована ли вложенная таблица
Если ВложеннаяТЗ <> Неопределено И ТипЗнч(ВложеннаяТЗ) = Тип("ТаблицаЗначений") Тогда
// Загружаем копию сохраненной таблицы
Комплект = ВложеннаяТЗ.Скопировать();
Иначе
// Если ячейка пустая, очищаем подчиненную таблицу
Комплект.Очистить();
КонецЕсли;
// Обновляем колонки подчиненного табличного поля
ЭлементыФормы.Комплект.СоздатьКолонки();
КонецФункции
Проанализируем ключевые особенности, которые необходимо учитывать при работе со сложными вложенными структурами:
ТаблицаЗначений не отображает внутренние строки. В текстовом виде пользователь увидит лишь надпись "Таблица значений".ТаблицаЗначений является объектным типом платформы, существующим только в оперативной памяти. Его нельзя напрямую записать в реквизит документа или справочника. Для сохранения такой структуры в БД ее необходимо упаковывать в ХранилищеЗначения или сериализовать (в JSON/XML).Скопировать() при каждом клике или переключении строки создает новые объекты в памяти. На больших объемах данных это может снижать производительность.Если структура данных предполагает иерархию, рассмотрим альтернативные штатные варианты платформы:
ДеревоЗначений): Если данные имеют древовидную структуру («Продукция» -> «Компоненты»), наилучшим решением будет использование `ДереваЗначений`. Элемент управления `ТабличноеПоле` умеет работать с деревом из коробки, предоставляя пользователю удобные плюсики для раскрытия и сворачивания строк.