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