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