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