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