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