Разработка и Конфигурация · 12 мин
Как программно добавить колонку в табличную часть на форме в 1С
Как программно добавить колонку в табличную часть формы в 1С 8.3: модификация реквизитов, ИзменитьРеквизиты, добавление ЭлементыФормы, примеры кода и типичные ошибки.
Задача программно добавить колонку в табличную часть на форме 1С возникает, когда состав колонок зависит от данных: например, нужно показать остатки по списку складов, цены по видам цен или показатели по периодам, а их набор заранее неизвестен. В управляемых формах это делается в два этапа: сначала изменяется состав реквизитов формы, затем создаётся элемент формы, связанный с новым реквизитом.
Ключевой момент: просто добавить элемент формы недостаточно — колонке нужен источник данных. Если табличная часть привязана к динамическому списку или к табличной части объекта, добавить в неё программно новую колонку данных нельзя. Поэтому типовой приём — перевести данные в динамический реквизит формы типа «ТаблицаЗначений» и уже в него добавлять колонки через метод ИзменитьРеквизиты().
Ниже разобран рабочий механизм для управляемых форм, отличия для обычных форм, ограничения платформы и типичные ошибки, из-за которых колонка либо не появляется, либо остаётся пустой.
Почему нельзя просто добавить колонку в табличную часть объекта
Табличная часть документа или справочника — это данные объекта, а не формы. Их состав фиксирован в конфигурации, и форма лишь отображает существующие реквизиты. Попытка добавить элемент формы с путём к данным, которого нет в объекте, приведёт к ошибке «Поле не найдено» при открытии формы.
То же ограничение действует для динамического списка: его колонки определяются запросом, а не составом элементов формы. Добавить туда вычисляемую колонку можно только через изменение текста запроса динамического списка, но это отдельный сценарий.
Поэтому стандартное решение — работать через динамический реквизит формы. Данные табличной части выгружаются в реквизит типа «ТаблицаЗначений» (или таблица создаётся с нуля), в неё добавляются нужные колонки, и форма отображает уже этот реквизит.
Шаг 1. Добавление реквизита-колонки через ИзменитьРеквизиты
Метод ИзменитьРеквизиты(ДобавляемыеРеквизиты, УдаляемыеРеквизиты) принимает два массива объектов типа «ОписаниеРеквизитаФормы». Для добавления колонки в таблицу значений формы у описания реквизита указывается имя, тип и путь — имя родительского реквизита-таблицы.
Порядок вызова важен: ИзменитьРеквизиты() можно выполнять только на сервере, в контексте формы. Обычно это делается в обработчике ПриСозданииНаСервере или в серверной процедуре, вызываемой по команде. После изменения состава реквизитов форма автоматически пересоздаётся с новой структурой данных.
&НаСервере
Процедура ДобавитьКолонкуНаСервере()
ДобавляемыеРеквизиты = Новый Массив;
ОписаниеРеквизита = Новый ОписаниеРеквизитаФормы(
"ОстатокНаСкладе", // имя колонки
Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)),
"ТоварыТаблица", // путь: реквизит-таблица формы
"Остаток на складе", // заголовок
Ложь);
ДобавляемыеРеквизиты.Добавить(ОписаниеРеквизита);
ИзменитьРеквизиты(ДобавляемыеРеквизиты);
КонецПроцедуры
Здесь ТоварыТаблица — динамический реквизит формы типа «ТаблицаЗначений», созданный заранее в конфигураторе или программно. Третий параметр конструктора — именно путь к родителю, без него реквизит добавится в корень формы, а не в таблицу.
Шаг 2. Создание элемента формы для новой колонки
После добавления реквизита данные в таблице уже есть, но пользователь их не увидит — нужен элемент формы. Колонка добавляется методом Элементы.Добавить() с типом Тип("ПолеФормы"), родителем указывается таблица формы, а свойство ПутьКДанным связывает элемент с реквизитом.
&НаСервере
Процедура ДобавитьЭлементКолонки()
НовыйЭлемент = Элементы.Добавить("ТоварыОстатокНаСкладе", Тип("ПолеФормы"), Элементы.ТоварыТаблица);
НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
НовыйЭлемент.ПутьКДанным = "ТоварыТаблица.ОстатокНаСкладе";
НовыйЭлемент.Заголовок = "Остаток на складе";
КонецПроцедуры
Имя элемента должно быть уникальным в пределах формы. Если процедура может выполняться повторно (например, при изменении отбора), сначала проверьте существование элемента через Элементы.Найти(), иначе получите ошибку дублирования имени.
ПутьКДанным строится по шаблону «ИмяТаблицы.ИмяКолонки». Ошибка в одной букве не всегда выявляется сразу: иногда колонка просто остаётся пустой, что затрудняет диагностику.
- 1Создайте на форме динамический реквизит типа «ТаблицаЗначений» и элемент-таблицу для его отображения
- 2В серверной процедуре сформируйте массив ОписаниеРеквизитаФормы с путём к таблице и вызовите ИзменитьРеквизиты()
- 3Добавьте элемент формы типа ПолеФормы с ПутьКДанным «Таблица.Колонка»
- 4Заполните данные: переберите строки реквизита-таблицы и присвойте значения новой колонке
- 5Проверьте результат, открыв форму: колонка видна и содержит значения
Шаг 3. Заполнение новой колонки данными
Добавленный реквизит изначально пуст: у всех строк таблицы значение новой колонки равно значению по умолчанию для типа (ноль, пустая строка, пустая ссылка). Заполнение выполняется обычным перебором строк реквизита формы.
&НаСервере
Процедура ЗаполнитьОстатки()
Для Каждого СтрокаТовара Из ТоварыТаблица Цикл
СтрокаТовара.ОстатокНаСкладе = ПолучитьОстаток(СтрокаТовара.Номенклатура);
КонецЦикла;
КонецПроцедуры
Если таблица большая, избегайте запросов в цикле — выгрузите номенклатуру в таблицу значений, выполните один запрос с соединением и заполните колонку по соответствию. Это принципиально для форм, которые открываются часто: десяток запросов в цикле на каждую строку заметно замедлит открытие.
Когда колонки добавляются динамически по списку (например, по каждому складу из отбора), весь цикл — добавление реквизита, элемента и заполнение — повторяется для каждой колонки внутри одного вызова ИзменитьРеквизиты(): сначала формируется полный массив реквизитов, потом одним вызовом они добавляются, и только затем создаются элементы.
Динамическое добавление и удаление колонок по условию
Типовой сценарий — перестраивать колонки при изменении настроек формы: пользователь выбрал другой период или другой набор складов, и состав колонок должен измениться. Здесь важно корректно удалять старые реквизиты и элементы перед добавлением новых.
Удаление делается тем же ИзменитьРеквизиты(), но массив удаляемых заполняется путями: "ТоварыТаблица.ОстатокНаСкладе". Элементы формы удаляются методом Элементы.Удалить() до или после изменения реквизитов — порядок не критичен, главное не оставить элемент, ссылающийся на несуществующий реквизит.
&НаСервере
Процедура ПерестроитьКолонки()
// Удаление старых колонок
УдаляемыеРеквизиты = Новый Массив;
Для Каждого ИмяКолонки Из СписокДинамическихКолонок Цикл
УдаляемыеРеквизиты.Добавить("ТоварыТаблица." + ИмяКолонки);
ЭлементКолонки = Элементы.Найти("Товары_" + ИмяКолонки);
Если ЭлементКолонки <> Неопределено Тогда
Элементы.Удалить(ЭлементКолонки);
КонецЕсли;
КонецЦикла;
ИзменитьРеквизиты(, УдаляемыеРеквизиты);
// Добавление новых колонок по актуальному списку
...
КонецПроцедуры
Список динамических колонок удобно хранить в реквизите формы (например, строка с именами через запятую или таблица значений), чтобы при перестроении знать, что именно удалять. Без такого реестра «осиротевшие» реквизиты будут накапливаться.
Особенности для обычных форм и альтернативные подходы
В обычных формах (режим обычного приложения) механика другая: там нет ИзменитьРеквизиты. Колонки добавляются напрямую в табличное поле через ЭлементыФормы.ТабличноеПоле.Колонки.Добавить(), а источником данных служит таблица значений, в которую колонка добавляется методом Колонки.Добавить(). Обычные формы встречаются всё реже, но в старых конфигурациях этот приём ещё актуален.
Если цель — не редактирование, а только отображение дополнительных данных, рассмотрите альтернативы без программного изменения реквизитов. Для динамического списка можно изменить текст запроса и добавить вычисляемое поле. Для отчётоподобных форм иногда проще вывести результат через СКД, где динамические колонки строятся настройками без единой строки кода по изменению формы.
Сравнение вариантов
Универсальный способ для управляемых форм. Подходит, когда колонки зависят от данных и нужно редактирование. Требует аккуратного удаления старых реквизитов
Подходит для списков, где колонки вычисляются запросом. Не работает для табличных частей объектов и не даёт редактируемых колонок
Подходит для отчётных форм без редактирования. Платформа сама строит колонки по настройкам, код минимален
Проверка результата и ограничения
После внедрения проверьте форму в трёх состояниях: при первом открытии, при повторном перестроении колонок и при записи объекта. При первом открытии колонка должна отображаться с данными. При перестроении не должно быть ошибок дублирования имён и «висячих» элементов. При записи убедитесь, что данные динамической таблицы не теряются неожиданно — реквизиты формы живут, пока жива форма.
Учтите ограничения: ИзменитьРеквизиты() нельзя вызывать в обработчиках ожидания и в некоторых событиях интерактивного изменения; состав реквизитов основного объекта изменить нельзя в принципе; программно добавленные элементы не сохраняются в настройках формы пользователя так же предсказуемо, как статические.
Как проверить результат
Колонка отображается с заданным заголовком
Колонки нет — проверьте, что элемент добавлен с правильным родителем (таблица формы)
Ячейки заполнены значениями по строкам
Колонка пустая — проверьте ПутьКДанным и код заполнения
Старые колонки исчезают, новые появляются без ошибок
Ошибка дублирования имени или ссылки на удалённый реквизит
Отдельно проверьте права и режим работы: в клиент-серверном варианте серверный вызов на каждое перестроение формы — это дополнительная нагрузка, поэтому перестройку колонок стоит делать по явному действию пользователя (кнопка, изменение отбора), а не на каждое событие формы.
Что важно запомнить
Колонка в табличную часть формы добавляется в два шага: ИзменитьРеквизиты() создаёт реквизит-колонку в динамической таблице значений формы, Элементы.Добавить() создаёт видимый элемент с ПутьКДанным «Таблица.Колонка». Напрямую в табличную часть объекта или динамический список колонку добавить нельзя. При перестроении сначала удаляйте старые реквизиты и элементы, храните реестр динамических колонок.
Частые вопросы
Можно ли добавить колонку непосредственно в табличную часть документа на форме?
Нет. Состав реквизитов табличной части фиксирован в метаданных объекта. Обходной путь — отображать данные через динамический реквизит формы типа «ТаблицаЗначений», куда табличная часть выгружается, и добавлять колонки уже в этот реквизит. При записи данные переносятся обратно в объект вручную.
Почему после ИзменитьРеквизиты колонка не появляется на форме?
Метод добавляет только данные, но не элемент интерфейса. Нужно дополнительно создать элемент формы методом Элементы.Добавить() с типом ПолеФормы, указать родителем таблицу формы и задать ПутьКДанным вида «ИмяТаблицы.ИмяКолонки».
Где вызывать ИзменитьРеквизиты — на клиенте или на сервере?
Только на сервере: в обработчике ПриСозданииНаСервере или в серверной процедуре формы. В клиентском контексте метод недоступен, и код завершится ошибкой. С клиента вызывайте серверную процедуру.
Как добавить сразу несколько колонок, например по списку складов?
Сформируйте один массив ОписаниеРеквизитаФормы для всех колонок и вызовите ИзменитьРеквизиты() один раз — это существенно быстрее, чем вызов в цикле. Затем в отдельном цикле создайте элементы формы и заполните данные. Имена колонок формируйте без спецсимволов, например «Склад_» + индекс, а соответствие склада и колонки храните в реквизите формы.
Колонка появилась, но пустая. В чём причина?
Чаще всего — ошибка в ПутьКДанным элемента или отсутствие кода заполнения. Проверьте, что путь точно совпадает с «ИмяТаблицы.ИмяРеквизита», и что после добавления реквизита выполняется перебор строк таблицы с присвоением значений новой колонке.
Как удалить программно добавленную колонку?
Вызовите ИзменитьРеквизиты() со вторым параметром — массивом путей удаляемых реквизитов вида «ТоварыТаблица.ОстатокНаСкладе», и удалите элемент формы через Элементы.Удалить(). Чтобы знать, что удалять, храните список динамических колонок в отдельном реквизите формы.