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