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