При разработке управляемых форм часто возникает необходимость реализовать нестандартный ввод данных: сформировать собственный выпадающий список через автоподбор и обработать результат выбора пользователя. Нередко разработчики сталкиваются с неприятной ситуацией: значение выбирается из списка, в обработчике выбора присваивается реквизиту формы, но текст в поле не отображается или сбрасывается, а стандартное событие ПриИзменении вовсе не вызывается. Разберем детально, почему это происходит и как правильно организовать работу с элементами формы.
Проанализируем типичный пример кода, который приводит к подобной ошибке:
&НаКлиенте
Процедура ПолеПоискаПоИННОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
ПолеПоискаПоИНН = ВыбранноеЗначение;
Элемент.ОбновитьТекстРедактирования();
КонецПроцедуры
В приведенном коде разработчик пытается напрямую присвоить реквизиту формы полученное значение и принудительно обновить текст элемента с помощью метода ОбновитьТекстРедактирования(). Однако строка остается пустой, а процедура ПриИзменении игнорируется платформой. Выясним внутренние механизмы платформы «1С:Предприятие 8», вызывающие такое поведение.
Выделим основные причины проблемы:
ПриИзменении генерируется платформой автоматически только тогда, когда штатный цикл выбора завершен. Если в процедуре ОбработкаВыбора разработчик отключает системное поведение установкой флага СтандартнаяОбработка = Ложь, платформа отменяет штатное присвоение значения реквизиту, не обновляет визуальный текст и не инициирует событие ПриИзменении.АвтоПодбор, но не настроено парное событие ОкончаниеВводаТекста, платформа при подтверждении ввода пытается сопоставить введенный текст по стандартным механизмам поиска (ввода по строке). Не найдя совпадений в базе, платформа считает ввод некорректным и принудительно очищает значение реквизита.ОбновитьТекстРедактирования(). Данный метод предназначен исключительно для обновления текста в момент, когда элемент находится в активном режиме интерактивного редактирования текста. Кроме того, его поведение регулируется свойством поля ОбновлениеТекстаРедактирования. Вне режима непосредственного набора текста вызов этого метода игнорируется платформой. Для обновления отображения формы на клиенте предназначен метод ЭтаФорма.ОбновитьОтображениеДанных().АвтоПодбор список ДанныеВыбора был заполнен значениями, тип которых не совпадает с типом реквизита формы (например, передана структура вместо строки или ссылка неподходящего справочника), платформа сбрасывает значение в значение по умолчанию.Рассмотрим наиболее правильный и простой способ обработки выбора. Если нам требуется изменить или откорректировать выбранные данные перед тем, как они попадут в реквизит, не следует выполнять прямое присвоение реквизиту и отключать платформенную обработку. Достаточно перезаписать значение в параметре ВыбранноеЗначение и оставить СтандартнаяОбработка = Истина.
Посмотрим на пример правильной реализации:
&НаКлиенте
Процедура ПолеПоискаПоИННОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
// Корректируем значение при необходимости
// Параметр СтандартнаяОбработка не трогаем (он равен Истина)
ВыбранноеЗначение = СокрЛП(ВыбранноеЗначение);
// Платформа сама запишет ВыбранноеЗначение в реквизит,
// обновит текст в поле и автоматически вызовет событие "ПриИзменении"
КонецПроцедуры
При таком подходе платформа выполняет полный штатный цикл: значение помещается в связанный реквизит формы, поле ввода корректно отображает представление, а затем автоматически вызывается обработчик ПриИзменении.
Если мы формируем список выбора динамически в обработчике АвтоПодбор, обязательно нужно перехватывать и событие ОкончаниеВводаТекста. Разберем по шагам, как настроить оба обработчика для поля ввода, чтобы платформа не сбрасывала результат после выхода из режима редактирования.
&НаКлиенте
Процедура ПолеПоискаПоИННАвтоПодбор(Элемент, Текст, ДанныеВыбора, Ожидание, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Формируем список возможных значений
ДанныеВыбора = Новый СписокЗначений;
ДанныеВыбора.Добавить("7701234567", "ООО Ромашка (ИНН 7701234567)");
ДанныеВыбора.Добавить("7809876543", "АО Вектор (ИНН 7809876543)");
КонецПроцедуры
&НаКлиенте
Процедура ПолеПоискаПоИННОкончаниеВводаТекста(Элемент, Текст, ДанныеВыбора, СтандартнаяОбработка)
// Обязательно отключаем стандартную обработку окончания ввода текста,
// чтобы платформа не пыталась найти соответствие по стандартным правилам
СтандартнаяОбработка = Ложь;
ДанныеВыбора = Новый СписокЗначений;
ДанныеВыбора.Добавить(Текст, Текст);
КонецПроцедуры
В этом случае платформа не пытается проверить введенный текст через стандартные механизмы и корректно передает управление в обработчик выбора.
Если специфика задачи требует полного отказа от стандартной обработки (например, при выборе значения нужно заполнить не один реквизит, а целую группу полей или строк табличной части), разберем, как корректно завершить процесс вручную.
Посмотрим на пример реализации с явным вызовом процедуры изменения:
&НаКлиенте
Процедура ПолеПоискаПоИННОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
// Полностью берем управление на себя
СтандартнаяОбработка = Ложь;
// Присваиваем значение реквизиту формы
ПолеПоискаПоИНН = ВыбранноеЗначение;
// Принудительно вызываем связанный обработчик изменения
ПолеПоискаПоИННПриИзменении(Элемент);
КонецПроцедуры
&НаКлиенте
Процедура ПолеПоискаПоИННПриИзменении(Элемент)
// Логика, которая должна выполниться при смене значения
Если ЗначениеЗаполнено(ПолеПоискаПоИНН) Тогда
// Выполняем действия по поиску или обработке данных
КонецЕсли;
КонецПроцедуры
Обратите внимание: если после установки значения реквизита поле ввода на форме визуально не обновилось, вызовем метод формы ЭтаФорма.ОбновитьОтображениеДанных(), который гарантированно синхронизирует отображение всех элементов с реквизитами формы.
Если поле ввода связано со ссылочным типом данных (например, справочником Контрагенты), наиболее устойчивым решением будет отказ от клиентского перехвата АвтоПодбор в пользу стандартного механизма платформы — события ОбработкаПолученияДанныхВыбора в модуле менеджера объекта.
Рассмотрим реализацию в модуле менеджера справочника:
// В модуле менеджера справочника Контрагенты
Процедура ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ДанныеВыбора = Новый СписокЗначений;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ТОП 10
| Контрагенты.Ссылка КАК Ссылка,
| Контрагенты.Наименование + "" (ИНН: "" + Контрагенты.ИНН + "")"" КАК Представление
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| Контрагенты.ИНН ПОДОБНО &СтрокаПоиска + ""%""";
Запрос.УстановитьПараметр("СтрокаПоиска", Параметры.СтрокаПоиска);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ДанныеВыбора.Добавить(Выборка.Ссылка, Выборка.Представление);
КонецЦикла;
КонецПроцедуры
Преимущества этого подхода очевидны: платформа самостоятельно контролирует все этапы ввода текста, паузы при наборе, навигацию клавишами со стрелками и выбор значения. При этом на форме штатно отрабатывают стандартные события ОбработкаВыбора и ПриИзменении без необходимости писать обходной код.