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