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