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

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

В процессе разработки на платформе 1С:Предприятие часто возникает задача отследить изменение значения реквизита, используя модель объекта для описания зависимостей. Стандартный обработчик события ПриИзменении срабатывает уже после того, как новое значение было записано в данные формы, и «старое» значение оказывается потеряно. Это создает сложности, если нам нужно, например, выдать предупреждение пользователю, отменить ввод или очистить связанные данные только при определенном условии — для этого подойдёт настройка логики изменения реквизитов без программирования. В данной статье мы разберем несколько проверенных методов, которые позволят нам получить доступ к обоим значениям — и к тому, которое было в поле до редактирования, и к новому.

Способ 1. Использование переменных модуля формы

Проанализируем самый универсальный способ, который подходит как для обычных, так и для управляемых форм (составить каркас кода поможет Консоль кода + ИИ-помощник) — для этого подойдёт инструментарий разработчика 1С с консолью кода. Идея заключается в том, чтобы создать переменную в модуле формы, которая будет выступать в роли временного буфера для хранения текущего значения. Давайте рассмотрим пошагово, как это реализовать.

Сначала мы объявляем переменную в самом верху модуля формы. Затем нам необходимо инициализировать её при открытии формы или при активации нужного поля. Рассмотрим пример реализации:


Перем ЗначениеДоИзменения;

Процедура ПриОткрытии()
    // Инициализируем начальное значение при открытии формы
    ЗначениеДоИзменения = ПолеВвода2;
КонецПроцедуры

Процедура ПолеВвода2ПриИзменении(Элемент)
    НовоеЗначение = Элемент.Значение;
    
    Сообщить("Старое значение: " + ЗначениеДоИзменения);
    Сообщить("Новое значение: " + НовоеЗначение);
    
    // После выполнения логики обновляем буферную переменную
    ЗначениеДоИзменения = НовоеЗначение;
КонецПроцедуры

Этот метод хорош тем, что он не требует обращений к базе данных и работает максимально быстро, а для отладки подойдет встраиваемая консоль кода — для этого подойдёт встраивая консоль отладки кода и переменных. Однако важно помнить о своевременном обновлении переменной ЗначениеДоИзменения, чтобы при следующем редактировании в ней снова хранилось актуальное предыдущее значение.

Способ 2. Сравнение со значением в базе данных (для записанных объектов)

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

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


&НаСервере
Функция ПолучитьСтароеЗначениеИзБазы()
    Возврат Объект.Ссылка.РеквизитЧисло;
КонецФункции

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

Важное ограничение: данный метод будет работать только для уже записанных объектов. Если вы создаете новый документ или элемент справочника, свойство Объект.Ссылка будет пустым, и получить старое значение таким образом не удастся.

Способ 3. Использование события ОкончаниеВводаТекста

Посмотрим на более продвинутый способ перехвата данных в момент, когда пользователь закончил ввод, но система еще не применила изменения к самому реквизиту. Событие ОкончаниеВводаТекста передает нам параметр Текст, который содержит то, что пользователь только что ввел. При этом сам реквизит (путь к данным) еще хранит старое значение.

Проанализируем пример кода для поля ввода даты:


&НаКлиенте
Процедура ДатаРегистрацииОкончаниеВводаТекста(Элемент, Текст, ДанныеВыбора, СтандартнаяОбработка)
    // В этот момент Объект.ДатаРегистрации еще содержит СТАРОЕ значение
    СтараяДата = Объект.ДатаРегистрации;
    
    // В параметре Текст находится НОВОЕ значение (в виде строки)
    Попытка
        НоваяДата = Дата(Текст);
        Сообщить("Вы меняете дату с " + СтараяДата + " на " + НоваяДата);
    Исключение
        // Обработка некорректного ввода
    КонецПопытки;
КонецПроцедуры

Этот метод позволяет реализовать интерактивные диалоги, например, спросить пользователя: «Вы уверены, что хотите изменить значение?». Если пользователь ответит «Нет», мы можем просто прервать процесс, не меняя данные.

Способ 4. Перехват значения в табличных частях

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

  1. Создаем переменную модуля ТекущееЗначениеЯчейки.
  2. В событии ПриАктивизацииЯчейки (или ПриНачалеРедактирования) записываем текущее значение в эту переменную.
  3. В событии ПриИзменении сравниваем новое значение с сохраненным в переменной.

Рассмотрим реализацию для числового поля в табличной части «Товары»:


&НаКлиенте
Перем ЗначениеЯчейкиДоИзменения;

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

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

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

Способ 5. Использование события ПриВходе (для Обычных форм)

В конфигурациях на обычных формах (например, УПП 1.3, как в вопросе автора) у элементов управления есть замечательное событие — ПриВходе. Оно срабатывает в тот момент, когда элемент получает фокус ввода. Это идеальное место для того, чтобы запомнить состояние реквизита перед тем, как пользователь начнет его менять.

Выясним, как это работает на практике. При входе в поле мы сохраняем значение в переменную модуля, а в ПриИзменении используем её для сравнения. Это избавляет от необходимости инициализировать переменные при открытии всей формы, что особенно полезно, если на форме очень много полей.

Резюме и рекомендации

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

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

← На главную