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

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

В процессе разработки конфигураций 1С часто возникает ситуация, когда табличная часть объекта (справочника, документа) содержит большое количество реквизитов — 10, 15 и более. Редактировать такие данные непосредственно в таблице неудобно: появляется горизонтальная прокрутка, теряется наглядность. Оптимальным решением в этом случае является создание отдельной, вспомогательной формы для редактирования одной выбранной строки. В качестве альтернативы ручной разработке можно использовать готовую универсальную форму ввода значений для редактирования произвольных структур данных.

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

Шаг 1. Подготовка основной формы и команды

В форме объекта, где находится наша табличная часть (назовем ее условно «Продукты»), необходимо создать команду, которая будет открывать форму редактирования строки.

  1. Добавьте новую команду в дерево команд формы, например, «РедактироватьСтроку».
  2. Перетащите эту команду в командную панель табличной части «Продукты». В свойствах команды укажите, чтобы она изменяла данные (свойство «Изменяет данные»).
  3. Создайте для команды обработчик действия на клиенте.

В этом обработчике мы сформируем все необходимое для открытия дочерней формы: параметры для передачи данных и описание оповещения для их возврата.

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

Проанализируем код обработчика команды:


&НаКлиенте
Процедура РедактироватьСтроку(Команда)
    // 1. Получаем текущие данные строки таблицы
    ТекущиеДанные = Элементы.Продукты.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        // Если строка не выбрана, ничего не делаем
        Возврат;
    КонецЕсли;

    // 2. Формируем структуру с данными для передачи
    ПараметрыПередачи = Новый Структура;
    
    // Вставляем все значения реквизитов строки.
    // Вместо ручного перебора используем ТекущиеДанные, которые уже являются структурой
    ЗаполнитьЗначенияСвойств(ПараметрыПередачи, ТекущиеДанные);
    
    // 3. ОБЯЗАТЕЛЬНО передаем идентификатор строки
    ПараметрыПередачи.Вставить("ИдентификаторСтроки", Элементы.Продукты.ТекущийИдентификатор);

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

    // 5. Открываем форму
    // "Справочник.Договоры.Форма.ФормаРедактированияПродукта" - путь к нашей доп. форме
    ОткрытьФорму(
        "Справочник.Договоры.Форма.ФормаРедактированияПродукта",
        ПараметрыПередачи,
        ЭтаФорма, // Владелец формы
        , // Уникальность
        , // Окно
        , // НавигационнаяСсылка
        Оповещение,
        РежимОткрытияОкнаФормы.БлокироватьОкноВладельца // Блокируем основную форму
    );
КонецПроцедуры

Важный момент: использование РежимОткрытияОкнаФормы.БлокироватьОкноВладельца предотвращает ситуацию, когда пользователь, не закрыв окно редактирования, может изменить или удалить эту же строку в основной форме, что приведет к ошибкам при возврате данных. Вместо всплывающего блокирующего окна можно реализовать альтернативный UX-паттерн и применить метод открытия формы внутри другой формы для встраивания интерфейса редактирования строки.

Шаг 2. Создание и настройка вспомогательной формы

Теперь создадим саму форму, в которой будет происходить редактирование. Пусть она называется «ФормаРедактированияПродукта».

  1. Создайте новую форму для справочника «Договоры».
  2. В реквизитах этой формы создайте реквизиты, которые полностью дублируют по именам и типам реквизиты табличной части «Продукты». Например, если в ТЧ есть реквизиты «Номенклатура» (тип СправочникСсылка.Номенклатура) и «Количество» (тип Число), то и в реквизитах формы должны быть созданы «Номенклатура» и «Количество» с теми же типами.
  3. Добавьте еще один реквизит — ИдентификаторСтроки (тип Число), чтобы хранить идентификатор, который мы передали.
  4. Разместите эти реквизиты на форме в удобном для пользователя виде.
  5. Добавьте на форму команды «ОК» (сделать ее кнопкой по умолчанию) и «Отмена».

Далее напишем код, который при открытии формы будет заполнять ее реквизиты из переданных параметров.


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Используем универсальный метод для заполнения реквизитов формы
    // Имена реквизитов формы и ключей в структуре "Параметры" должны совпадать
    ЗаполнитьЗначенияСвойств(ЭтотОбъект, Параметры);
КонецПроцедуры

Метод ЗаполнитьЗначенияСвойств избавляет от необходимости писать длинный код вида ЭтаФорма.Реквизит1 = Параметры.Реквизит1 для каждого из 10+ полей. Это просто, эффективно и легко поддерживать.

Шаг 3. Возврат измененных данных из вспомогательной формы

Когда пользователь отредактирует данные и нажмет «ОК», нам нужно собрать измененные значения и передать их обратно в основную форму. Это делается в обработчике команды «ОК».


&НаКлиенте
Процедура ОК(Команда)
    // Создаем структуру для возврата данных
    РезультатРедактирования = Новый Структура;

    // Заполняем структуру значениями из реквизитов формы.
    // Обратите внимание, здесь мы делаем обратную операцию:
    // источник - форма (ЭтотОбъект), приемник - структура (РезультатРедактирования)
    ЗаполнитьЗначенияСвойств(РезультатРедактирования, ЭтотОбъект);

    // Закрываем форму и передаем структуру в качестве результата
    Закрыть(РезультатРедактирования);
КонецПроцедуры

Для команды «Отмена» достаточно стандартного действия закрытия формы. В этом случае результат будет Неопределено, и мы сможем это обработать.

Шаг 4. Обработка возвращенных данных в основной форме

Вернемся в основную форму. Мы готовы принять данные, которые вернула вспомогательная форма. Для этого создадим процедуру-обработчик, имя которой мы указали в ОписаниеОповещения — «ПослеРедактированияСтроки».


&НаКлиенте
Процедура ПослеРедактированияСтроки(РезультатЗакрытия, ДополнительныеПараметры) Экспорт
    // Проверяем, что пользователь нажал "ОК", а не "Отмена"
    Если РезультатЗакрытия = Неопределено Тогда
        Возврат;
    КонецЕсли;

    // Данные формы (Объект) можно изменять только на сервере
    ОбновитьДанныеСтрокиНаСервере(РезультатЗакрытия);
    
    // Устанавливаем признак, что данные были изменены
    Модифицированность = Истина;
КонецПроцедуры

&НаСервере
Процедура ОбновитьДанныеСтрокиНаСервере(ЗначенияДляОбновления)
    // Находим строку в объекте по идентификатору, который мы сохранили и вернули
    ДанныеСтроки = Объект.Продукты.НайтиПоИдентификатору(ЗначенияДляОбновления.ИдентификаторСтроки);
    
    Если ДанныеСтроки <> Неопределено Тогда
        // Заполняем найденную строку данными из возвращенной структуры
        ЗаполнитьЗначенияСвойств(ДанныеСтроки, ЗначенияДляОбновления);
    КонецЕсли;
КонецПроцедуры

Разберем этот код:

  1. Процедура ПослеРедактированияСтроки вызывается автоматически после закрытия дочерней формы. В ее первом параметре РезультатЗакрытия находится та самая структура, которую мы передали через Закрыть(...).
  2. Мы проверяем, что результат не равен Неопределено.
  3. Для изменения данных объекта (Объект.Продукты) мы вызываем серверную процедуру.
  4. На сервере с помощью метода НайтиПоИдентификатору мы надежно находим нужную строку.
  5. И снова используем ЗаполнитьЗначенияСвойств, чтобы обновить все поля строки за одну команду.
  6. Установка свойства Модифицированность = Истина сообщает платформе, что объект был изменен, и при закрытии основной формы будет задан вопрос о сохранении.

Дополнительно: обработка создания новой строки

Этот же механизм можно легко адаптировать и для добавления новой строки. Для этого в основной форме нужно создать команду «ДобавитьСтроку».

Отличие в коде будет минимальным:

  1. В обработчике команды «ДобавитьСтроку» вы не передаете текущие данные и идентификатор. Просто открываете форму с пустыми параметрами.
  2. Во вспомогательной форме в ПриСозданииНаСервере можно установить какие-то значения по умолчанию.
  3. В обработчике ПослеРедактированияСтроки нужно добавить проверку: если в РезультатЗакрытия нет ИдентификаторСтроки, значит, это новая строка. В этом случае на сервере нужно использовать не НайтиПоИдентификатору, а Объект.Продукты.Добавить(), а затем заполнить новую строку данными.

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

← На главную