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