При разработке интерфейсов в «1С:Предприятие 8» часто возникает задача предоставить пользователю возможность выбора нескольких значений из списка в одно поле. Например, в поле «Цвета» необходимо выбрать сразу несколько вариантов: «Красный», «Синий», «Зеленый». По умолчанию стандартное поведение платформы при выборе значения из выпадающего списка заменяет предыдущую запись новой. В этой статье мы подробно разберем, как обойти это ограничение и реализовать добавление выбранных значений через запятую (или другой разделитель) без стирания ранее введенных данных.
Мы рассмотрим несколько подходов к решению этой задачи: от классического программного переопределения стандартной обработки события выбора до использования современных штатных механизмов платформы 1С, появившихся в последних версиях.
Этот способ является классическим и подходит практически для любой версии платформы «1С:Предприятие 8» (как для управляемых, так и для обычных форм). Суть метода заключается в том, что мы перехватываем стандартное событие выбора элемента из списка, отменяем его стандартное поведение и самостоятельно дописываем выбранное значение к уже существующей строке.
Давайте разберем по шагам, как это реализовать на управляемой форме:
Строка. Назовем его, например, ОсмотрРегулярно.РежимВыбораИзСписка в значение Истина.СписокВыбора) необходимыми значениями (например: "Красный", "Синий", "Зеленый").ОбработкаВыбора для нашего поля ввода.Теперь напишем код обработчика события. Нам необходимо отключить стандартную обработку системы, проверить, заполнено ли уже наше поле ввода, и добавить новое значение через запятую.
&НаКлиенте
Процедура ОсмотрРегулярноОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
// Отменяем стандартное поведение платформы, которая затирает поле новым значением
СтандартнаяОбработка = Ложь;
// Определяем, нужен ли разделитель (запятая с пробелом).
// Если поле еще пустое, разделитель не нужен.
СтрокаЗапятая = ?(ЗначениеЗаполнено(СокрЛП(ОсмотрРегулярно)), ", ", "");
// Складываем предыдущее значение поля, разделитель и новое выбранное значение
ОсмотрРегулярно = ОсмотрРегулярно + СтрокаЗапятая + ВыбранноеЗначение;
КонецПроцедуры
Проанализируем этот код подробнее. Ключевым моментом здесь является строка СтандартнаяОбработка = Ложь;. Именно она сообщает платформе, что мы берем управление процессом выбора на себя. Если этого не сделать, платформа после выполнения нашей процедуры все равно запишет в поле только одно последнее выбранное значение, проигнорировав все наши программные сложения.
Обратите внимание на использование тернарного оператора ?(). Он позволяет лаконично проверить, пустая ли строка в реквизите ОсмотрРегулярно. Если она не пустая, переменной СтрокаЗапятая присваивается значение ", ", иначе — пустая строка "". Это гарантирует, что в самом начале строки у нас не появится лишняя запятая.
Если ваша конфигурация работает на версии платформы «1С:Предприятие» 8.3.23 или новее, вам больше не нужно писать программный код для склеивания строк. Фирма «1С» реализовала полноценный штатный механизм под названием «Множественный выбор в поле ввода».
Этот механизм визуально очень удобен для пользователя и напоминает современные веб-интерфейсы. Выбранные значения отображаются в поле ввода в виде компактных блоков — «чипсов» (тегов), а в самом выпадающем списке рядом с элементами появляются флажки (чекбоксы).
Давайте настроим этот механизм:
СписокЗначений (а не Строка, как в предыдущем примере). Тип типа данных списка должен соответствовать типу выбираемых значений (например, Строка или ссылка на справочник).РежимВыбораИзСписка и установите его в значение Истина.При запуске в режиме «1С:Предприятие» пользователь увидит выпадающий список, в котором сможет просто отмечать галочками нужные элементы. Платформа сама скомпонует их в красивую строку. Более того, это полностью решает проблему ошибочного выбора: если пользователь случайно выбрал не тот цвет, ему не нужно вручную стирать текст. Он может просто нажать на крестик «х» на соответствующем «чипсе» прямо в поле ввода или снять галочку в списке выбора.
Если вам необходимо реализовать выбор элементов из фиксированного списка, но вы хотите предоставить пользователю полноценное диалоговое окно с флажками (особенно актуально для старых версий платформы, где еще нет встроенных «чипсов»), можно использовать стандартный метод объекта СписокЗначений — ОтметитьЭлементы().
Рассмотрим пример реализации через команду на форме. Предположим, у нас есть кнопка выбора и текстовое поле ВыбранныеЦвета, куда мы хотим поместить результат.
&НаКлиенте
Процедура ВыбратьЦветаВыполнить()
// Создаем список доступных значений для выбора
СписокЦветов = Новый СписокЗначений;
СписокЦветов.Добавить("Красный");
СписокЦветов.Добавить("Синий");
СписокЦветов.Добавить("Зеленый");
СписокЦветов.Добавить("Желтый");
// Если в нашем текстовом поле уже есть выбранные значения,
// мы можем программно отметить их в списке перед показом диалога
Если ЗначениеЗаполнено(ВыбранныеЦвета) Тогда
Для Каждого ЭлементСписка Из СписокЦветов Цикл
// Если имя цвета содержится в нашей строке, ставим пометку
Если Найти(ВыбранныеЦвета, ЭлементСписка.Значение) > 0 Тогда
ЭлементСписка.Пометка = Истина;
КонецЕсли;
КонецЦикла;
КонецЕсли;
// Вызываем стандартное окно отметки элементов
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеВыбораЦветов", ЭтотОбъект);
СписокЦветов.ПоказатьОтметкуЭлементов(ОписаниеОповещения, "Выберите цвета из списка:");
КонецПроцедуры
&НаКлиенте
Процедура ПослеВыбораЦветов(ВыбранныйСписок, ДополнительныеПараметры) Экспорт
// Если пользователь закрыл окно или нажал Отмена, возвращается Неопределено
Если ВыбранныйСписок = Неопределено Тогда
Возврат;
КонецЕсли;
// Обходим отмеченные элементы и собираем их в строку через запятую
РезультатСтрокой = "";
Для Каждого ЭлементСписка Из ВыбранныйСписок Цикл
Если ЭлементСписка.Пометка Тогда
Разделитель = ?(ПустаяСтрока(РезультатСтрокой), "", ", ");
РезультатСтрокой = РезультатСтрокой + Разделитель + ЭлементСписка.Значение;
КонецЕсли;
КонецЦикла;
// Записываем результат в реквизит формы
ВыбранныеЦвета = РезультатСтрокой;
КонецПроцедуры
Этот метод очень дружелюбен к пользователю: перед ним открывается полноценное окно, где можно быстро отметить галочками нужные позиции, нажать кнопку «ОК», после чего система автоматически сформирует красивую строку. В качестве готового решения для подобного сценария подойдёт универсальная форма для ввода нескольких значений различных типов.
В реальных задачах список значений часто формируется не вручную в коде, а выбирается из справочника (например, справочник «Номенклатура» или «Цвета»). Если список элементов слишком велик для обычного выпадающего меню, правильнее использовать стандартную форму выбора с включенным режимом множественного выделения. Для реализации множественного выбора через пометки элементов в списке подойдёт способ добавления флажков в динамический список.
Разберем, как открыть форму выбора справочника в режиме множественного выделения и обработать полученный массив данных:
&НаКлиенте
Процедура ВыбратьЦветаИзСправочника(Элемент)
// Настраиваем параметры открытия формы выбора справочника
ПараметрыВыбора = Новый Структура;
ПараметрыВыбора.Вставить("МножественныйВыбор", Истина);
ПараметрыВыбора.Вставить("ЗакрыватьПриВыборе", Ложь); // Форма не закроется после клика, позволяя выбрать еще
// Открываем форму выбора справочника "Цвета"
ОткрытьФорму("Справочник.Цвета.ФормаВыбора", ПараметрыВыбора, Элемент);
КонецПроцедуры
После того как пользователь выделит несколько элементов в справочнике (зажав клавишу Ctrl или Shift) и нажмет кнопку выбора, на исходной форме сработает событие ОбработкаВыбора. В параметре ВыбранноеЗначение придет не одно значение, а Массив ссылок. Нам останется только обойти этот массив программно:
&НаКлиенте
Процедура ВыбранныеЦветаОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Проверяем, что нам вернулся массив (при множественном выборе)
Если ТипЗнч(ВыбранноеЗначение) = Тип("Массив") Тогда
Для Каждого СсылкаНаЦвет Из ВыбранноеЗначение Цикл
Разделитель = ?(ЗначениеЗаполнено(СокрЛП(ВыбранныеЦвета)), ", ", "");
ВыбранныеЦвета = ВыбранныеЦвета + Разделитель + Строка(СсылкаНаЦвет);
КонецЦикла;
Иначе
// Одиночный выбор (если пользователь выбрал только один элемент)
Разделитель = ?(ЗначениеЗаполнено(СокрЛП(ВыбранныеЦвета)), ", ", "");
ВыбранныеЦвета = ВыбранныеЦвета + Разделитель + Строка(ВыбранноеЗначение);
EndIf;
КонецПроцедуры
В процессе обсуждения этой задачи на форуме опытные разработчики справедливо замечают: хранение множественного выбора в виде одной текстовой строки через запятую в базе данных — это плохая практика. Давайте выясним причины, почему этого стоит избегать:
"Красный, Синий", вы не сможете быстро построить отчет по продажам товаров конкретно "Красного" цвета. Придется использовать крайне медленные запросы с оператором ПОДОБНО "%Красный%", что приведет к сильному падению производительности на больших базах данных.Как делать правильно?
Для временного отображения информации на форме текстовая строка через запятую подходит отлично. Но в самой базе данных информацию о множественном выборе рекомендуется хранить одним из следующих способов:
ЦветаТовара) с одной колонкой Цвет (тип — ссылка на справочник). При записи объекта программа должна программно парсить вашу строку (или брать исходный список) и заполнять эту табличную часть.Таким образом, мы детально разобрали как визуальную сторону настройки интерфейса подбора элементов, так и архитектурные аспекты проектирования метаданных для хранения результатов множественного выбора.