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