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

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

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

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


// Пример кода, который НЕ сохраняет данные
Должность = ЭтотОбъект.Элементы.Найти("Должность");
Если Должность = Неопределено Тогда		
	НовыйРеквизит = Новый РеквизитФормы("Должность", Новый ОписаниеТипов("Строка"), "Объект.Начисления", "Должность", Истина); 
	
	ДобавленныеРеквизиты = Новый Массив;
	ДобавленныеРеквизиты.Добавить(НовыйРеквизит);	
	ЭтотОбъект.ИзменитьРеквизиты(ДобавленныеРеквизиты); 
КонецЕсли;

ЭлементДолжность 				= ЭтаФорма.Элементы.Вставить("Должность", Тип("ПолеФормы"), ЭтаФорма.Элементы.Начисления, ЭтаФорма.Элементы.НачисленияПодразделение); 
ЭлементДолжность.Вид 			= ВидПоляФормы.ПолеВвода;
ЭлементДолжность.ПутьКДанным 	= "Объект.Начисления.Должность"; // Ключевой момент
ЭлементДолжность.Заголовок 		= "Должность";

На первый взгляд, все логично: мы создаем реквизит формы, добавляем на форму элемент управления (колонку) и связываем их. Но именно здесь и кроется корень проблемы.

Выясним причину: Реквизит Формы vs. Реквизит Объекта

Чтобы понять, почему данные пропадают, разберемся с двумя фундаментальными понятиями в 1С:

  1. Реквизит Объекта — это атрибут, описанный в метаданных конфигурации (например, у документа, справочника). Он является частью структуры данных объекта и физически хранится в таблице базы данных. Платформа 1С автоматически управляет чтением этих данных при открытии формы объекта и их записью в базу данных при его сохранении.
  2. Реквизит Формы — это временная переменная, которая существует только в памяти, пока открыта конкретная форма. Реквизиты формы используются для хранения промежуточных данных, параметров, флагов видимости/доступности и прочей информации, необходимой для логики работы формы. Эти данные не сохраняются в базу данных автоматически.

В приведенном выше коде с помощью Новый РеквизитФормы(...) создается именно временный реквизит. Далее, в строке ЭлементДолжность.ПутьКДанным = "Объект.Начисления.Должность", происходит попытка связать элемент формы с реквизитом объекта. Но поскольку реквизита "Должность" в метаданных табличной части "Начисления" документа "Премия" нет, платформа не может сохранить данные. Для нее этот путь ведет в никуда.

Таким образом, главная ошибка — попытка сохранить данные в несуществующем поле базы данных, работая при этом только с временными данными формы.

Решение 1: Правильный способ с сохранением данных (через расширение)

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

Разберем по шагам, как это сделать с помощью механизма расширений:

  1. Создайте новое расширение. В конфигураторе откройте меню "Конфигурация" -> "Расширения конфигурации" и добавьте новое расширение.
  2. Заимствуйте объект. Найдите в дереве конфигурации нужный объект (в нашем случае — Документ "Премия") и добавьте его в расширение.
  3. Добавьте реквизит в табличную часть. Откройте заимствованный документ в расширении. Перейдите на вкладку "Данные". Найдите табличную часть "Начисления", раскройте ее и добавьте новый реквизит. Назовем его Должность, тип — Строка.
  4. Сохраните изменения. Обновите конфигурацию базы данных (F7).

Поздравляем! Теперь в структуре документа "Премия" есть полноценный реквизит Должность, и платформа "знает", как и куда сохранять его значение.

Теперь вернемся к форме. После добавления реквизита в объект у нас есть два пути:

Код для программного добавления колонки и кнопки в обработчике ПриСозданииНаСервере теперь будет выглядеть так:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

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

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

		НоваяКнопкаФормы = ЭтаФорма.Элементы.Вставить(НоваяКоманда.Имя, Тип("КнопкаФормы"), ЭтаФорма.КоманднаяПанель);
		НоваяКнопкаФормы.ИмяКоманды = НоваяКоманда.Имя;
	КонецЕсли;

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

&НаКлиенте
Процедура ПроставитьДолжность(Команда)
	// Здесь код заполнения должности для каждой строки
	ПроставитьДолжностьНаСервере();
КонецПроцедуры

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

При нажатии на кнопку "Записать" платформа автоматически сохранит все данные из Объект.Начисления, включая нашу новую колонку Должность, в базу данных.

Решение 2: Динамическое отображение без сохранения

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

Как это работает:

  1. Добавляем реквизит формы. Нам нужно создать реквизит формы, который будет соответствовать нашей колонке. Но его путь должен быть привязан к данным таблицы на форме, а не к объекту. Например, если таблица на форме называется Начисления, то путь к данным будет Начисления.Должность.
  2. Программно заполняем данные. В обработчике события ПриОткрытии или ПриСозданииНаСервере нужно обойти строки табличной части и для каждой строки заполнить значение в нашей новой, "виртуальной" колонке.
  3. Обновляем данные при изменении. Также необходимо добавить обработчик события ПриИзменении для колонки "Сотрудник" в таблице. Когда пользователь выберет другого сотрудника, код должен будет получить его должность и обновить значение в колонке "Должность".

Этот подход полезен для отображения вычисляемой или справочной информации, но важно помнить: при записи и повторном открытии документа эти данные будут утеряны и должны быть рассчитаны заново.

В итоге, ключ к решению проблемы — это четкое понимание, где должны храниться данные. Если информация должна быть постоянной и сохраняться вместе с документом, ей необходимо место в структуре объекта в базе данных, которое создается через конфигуратор или расширение. Если же информация временная и нужна только для отображения на форме, достаточно реквизитов формы.

← На главную