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