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