При разработке интерфейсов на управляемых формах часто возникает задача связать две таблицы значений по принципу «мастер — деталь». Типичный пример: в первой таблице отображается список заказов, а во второй — перечень упаковок или товарных позиций, относящихся к текущему заказу. При переходе по строкам первой таблицы подчиненная таблица должна мгновенно фильтроваться.
Для реализации такой фильтрации разработчики обычно используют свойство таблицы формы ОтборСтрок в обработчике события ПриАктивизацииСтроки. Однако при работе со строковыми полями многие сталкиваются с неожиданным поведением платформы: отбор работает не по точному равенству, а по вхождению подстроки.
Разберем подробнее, почему так происходит, и рассмотрим проверенные способы организовать отбор по строгому соответствию значений.
Проанализируем исходный фрагмент кода, приводящий к проблеме:
ТекДанные = Элементы.СписокЗаказов.ТекущиеДанные;
Если ТекДанные = Неопределено Тогда
Элементы.СписокУпаковок.ОтборСтрок = Неопределено;
Иначе
Элементы.СписокУпаковок.ОтборСтрок = Новый ФиксированнаяСтруктура("НомерЗаказа", ТекДанные.НомерЗаказа);
КонецЕсли;
Если номер текущего заказа равен «1», то в подчиненной таблице отобразятся не только строки с номером «1», но и «10», «11», «21» и любые другие, где встречается единица.
Дело в архитектурном ограничении механизма ОтборСтрок на управляемых формах:
ОтборСтрок принимает исключительно объект типа ФиксированнаяСтруктура (или значение Неопределено для сброса отбора). В отличие от обычных форм (где объектом выступал Отбор с возможностью явно задать ВидСравнения.Равно), в управляемом интерфейсе возможность указать вид сравнения отсутствует.Выясним причину и рассмотрим несколько практических вариантов решения задачи.
Самый надежный и правильный с точки зрения архитектуры 1С подход — выполнять связывание таблиц не по номеру заказа, а по уникальной ссылке на сам документ. Для ссылочных типов платформа выполняет проверку строго на равенство.
Посмотрим на пример кода в обработчике активизации строки:
ТекДанные = Элементы.СписокЗаказов.ТекущиеДанные;
Если ТекДанные = Неопределено Тогда
Элементы.СписокУпаковок.ОтборСтрок = Неопределено;
Иначе
ПараметрыОтбора = Новый Структура("СсылкаНаЗаказ", ТекДанные.СсылкаНаЗаказ);
Элементы.СписокУпаковок.ОтборСтрок = Новый ФиксированнаяСтруктура(ПараметрыОтбора);
КонецЕсли;
Для реализации этого метода необходимо добавить поле Ссылка в запрос, формирующий обе таблицы значений на сервере. Это исключит любые ложные срабатывания фильтра.
Если номера заказов состоят только из цифр, а менять логику формирования данных и добавлять ссылки нежелательно, можно привести колонку связи к числовому типу. Числа, как и ссылки, сравниваются строго на равенство.
Число()).НомерЗаказа в реквизитах формы как Число.ФиксированнаяСтруктура:
Если ТекДанные <> Неопределено Тогда
Элементы.СписокУпаковок.ОтборСтрок = Новый ФиксированнаяСтруктура("НомерЗаказа", Число(ТекДанные.НомерЗаказа));
КонецЕсли;
При таком подходе число 1 никогда не совпадет с числом 10 или 21.
Если номера содержат буквы, префиксы или дефисы и не могут быть преобразованы в числа, применим один из двух приемов форматирования строк:
"0000000001" и "0000000010"), строка "0000000001" физически не содержится внутри "0000000010", что исключает пересечения."#1#", "#10#". При установке отбора передаем значение "#1#". Поскольку подстрока "#1#" отсутствует внутри строки "#10#", платформа отобразит только требуемые строки.Если данные загружаются из внешнего источника или формируются вычислениями без привязки к ссылкам базы данных, надежным решением станет генерация уникального ключа строки при первичном заполнении таблиц на сервере.
Разберем по шагам:
КлючСвязи с длиной 36 символов.Строка(Новый УникальныйИдентификатор).Поскольку GUID состоит из 36 символов и обладает абсолютной уникальностью, вероятность случайного совпадения подстрок сведена к нулю.
Если требуется оставить исходную структуру колонок без добавления вспомогательных полей, можно отказаться от визуального свойства таблицы ОтборСтрок и управлять содержимым подчиненной таблицы вручную.
В отличие от свойства формы ОтборСтрок, программный метод коллекции НайтиСтроки() для строковых полей выполняет поиск строго по точному совпадению.
Рассмотрим схему реализации:
ВсеУпаковки).СписокУпаковок отображаем только отфильтрованный результат.ПриАктивизацииСтроки очищаем отображаемую таблицу и копируем в нее строки, полученные методом НайтиСтроки().Посмотрим на пример кода:
&НаКлиенте
Процедура СписокЗаказовПриАктивизацииСтроки(Элемент)
ТекДанные = Элементы.СписокЗаказов.ТекущиеДанные;
СписокУпаковок.Очистить();
Если ТекДанные <> Неопределено Тогда
ПараметрыПоиска = Новый Структура("НомерЗаказа", ТекДанные.НомерЗаказа);
НайденныеСтроки = ВсеУпаковки.НайтиСтроки(ПараметрыПоиска);
Для Каждого СтрНайдено Из НайденныеСтроки Цикл
ЗаполнитьЗначенияСвойств(СписокУпаковок.Добавить(), СтрНайдено);
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Важный нюанс: при программном изменении строк в подчиненной таблице (если используется свойство ОтборСтрок), отбор необходимо переустанавливать повторно, чтобы вновь добавленные или отредактированные элементы корректно скрывались или отображались в форме.