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