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