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