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