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