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

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

В процессе разработки на платформе 1С:Предприятие 8.3 (особенно в управляемых формах) программисты часто сталкиваются с задачей: при изменении значения в строке табличной части необходимо знать, каким это значение было до редактирования. Стандартное событие ПриИзменении (как для элемента формы, так и для реквизита) срабатывает тогда, когда новые данные уже записаны в реквизит формы. Попытка обратиться к Элементы.ИмяТаблицы.ТекущиеДанные в этот момент вернет уже новое, измененное значение.

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

Почему данные в событии ПриИзменении уже обновлены?

Выясним причину такого поведения платформы. В управляемом интерфейсе существует четкое разделение между данными на сервере, данными в реквизитах формы и отображением этих данных в элементах управления на клиенте. Когда пользователь завершает ввод в ячейку (нажимает Enter или переходит в другое поле), происходит синхронизация: данные из поля ввода переносятся в соответствующий реквизит коллекции (строку табличной части). Только после того, как значение в структуре данных обновлено, платформа вызывает событие ПриИзменении.

Иногда разработчики замечают странное поведение, когда в расширениях (используя аннотации &Перед) данные кажутся «старыми». Однако полагаться на это нельзя, так как это зависит от версии платформы и конкретного типа данных. Для стабильной работы бизнес-логики мы рассмотрим гарантированные методы фиксации состояния «до».

Способ 1: Использование скрытой колонки (Best Practice)

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

Проанализируем шаги реализации:

  1. В табличную часть объекта (или только в реквизиты формы, если данные не нужно хранить в базе) добавим колонку, например, КоличествоСтарое.
  2. В событии формы ПриЧтенииНаСервере или ПриСозданииНаСервере заполним эту колонку текущими значениями.
  3. В обработчике ПриИзменении основной колонки будем использовать значение из скрытой колонки для расчетов, а в конце процедуры — обновлять скрытую колонку новым значением.

Пример кода для реализации пересчета:


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

Способ 2: Кэширование через переменную модуля формы

Если вы не хотите перегружать структуру табличной части дополнительными реквизитами (особенно если строк очень много), можно воспользоваться кэшированием в переменной на клиенте. Для этого нам понадобятся события таблицы ПриНачалеРедактирования или ПриАктивизацииСтроки.

Рассмотрим алгоритм действий:

  1. Объявим переменную в модуле формы.
  2. В момент, когда пользователь только заходит в строку или начинает ее менять, сохраним текущее значение в эту переменную.
  3. В событии ПриИзменении обратимся к этой переменной.

Посмотрим на пример кода:


&НаКлиенте
Перем ЗначениеДоИзменения; // Переменная в начале модуля

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

&НаКлиенте
Процедура ТоварыКоличествоПриИзменении(Элемент)
    
    ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
    
    // Теперь у нас есть и старое, и новое значение
    Сообщить("Было: " + ЗначениеДоИзменения);
    Сообщить("Стало: " + ТекущиеДанные.Количество);
    
    // После обработки можем обновить кэш
    ЗначениеДоИзменения = ТекущиеДанные.Количество;
    
КонецПроцедуры

Важный нюанс: Событие ПриНачалеРедактирования срабатывает один раз при открытии строки. Если пользователь изменит значение несколько раз, не выходя из строки, переменная ЗначениеДоИзменения будет хранить самое первое значение. Если вам нужно значение, которое было «секунду назад» до последнего ввода, обновляйте переменную в конце каждого ПриИзменении.

Способ 3: Перехват через ПередОкончаниемРедактирования

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

Особенности работы с программным изменением

Проанализируем ситуацию, упомянутую в обсуждении: когда изменение одной колонки (Колонка 1) должно приводить к пересчету другой (Колонка 2), и наоборот. Важно помнить: когда вы программно присваиваете значение реквизиту (например, Объект.Товары[0].Цена = 100;), событие ПриИзменении для этого элемента формы не вызывается автоматически.

Чтобы избежать зацикливания и корректно обработать такие зависимости, рекомендуем придерживаться следующей структуры:

Рекомендация по архитектуре коэффициентов

Если ваша задача — расчет обратной зависимости (как в сообщении 15 форума), то хранение исходного коэффициента в скрытой колонке — самый безопасный путь. Это избавляет систему от необходимости «вспоминать», что было введено ранее, и позволяет корректно работать даже после закрытия и открытия формы или при выполнении групповых обработок строк табличной части на сервере.

Подводя итог, можно сказать: хотя прямого доступа к «старым» данным в событии ПриИзменении нет, комбинация обработчика ПриНачалеРедактирования и скрытых реквизитов формы полностью решает эту задачу, обеспечивая точность расчетов и удобство пользователя. Для контроля и отладки значений в таких невидимых полях на этапе тестирования пригодится утилита для отображения скрытых реквизитов управляемых форм.

← На главную