Часто возникает необходимость фильтровать значения одного системного виджета фильтра в зависимости от значений другого. К примеру, при выборе региона отображать только относящиеся к нему достопримечательности. На момент актуальной версии AW 1.25 реализовать такой функционал можно через HTML-виджет и функцию setFilter. Рассмотрим на примере.
Подготовка данных для фильтров
В первую очередь нам необходимо получить в модели маппинг для значений фильтров. Это можно сделать через новую промежуточную модель в которой выведем уникальные строки в виде «Регион» - «Тип достопримечательности». При необходимости использования других показателей или их количества принцип остается тем же. Пример данных для модели фильтрации представлен на рисунке. После создание модели не забудем загрузить данные в хранилище.
Создание HTML-виджета с фильтрами
Теперь создадим на этой модели виджет с типом HTML. В «Столбцы» добавим поля «Регион», «Достопримечательность»(1) без применения агрегации для получения плоской таблицы(2).
Теперь перейдем непосредственно к коду. В первую очередь создадим div-контейнеры и select-элементы на вкладке HTML.
код HTML
<div class="filters-container">
<select class="filter region-filter">
</select>
<select class="filter attr-filter">
</select>
</div>
Также добавим базовую стилизацию на вкладке CSS.
код CSS
.filters-container {
width: 100%;
height: 100%;
}
.filter {
border-radius: 12px;
flex: 1;
padding: 0 16px 0 6px;
overflow: hidden;
color: black;
min-width: 45%;
max-width: 50%;
min-height: 30px;
box-shadow: 0px 5px 10px -3px rgba(0,0,0,0.1);
}
.filter option {
color: black;
}
Осталось самое интересное: добавить JS код, где будем заполнять значения фильтров и добавим логику их применения. Данные для фильтров будут доступны в объекте window.DATA.data в виде массива объектов с полями, добавленным в столбцы.
Общий алгоритм для вкладки JS следующий:
- При первой отрисовке виджета необходимо получить списки для значений каждого из фильтров и иерархический маппинг между ними.
- Для списков значений сгенерировать объекты option и добавить в соответствующий select
- К полученным фильтрам добавить обработчик, в котором вызывать функцию setFilter, которая отфильтрует данные модели.
Пример реализации представлен ниже. Необходимо учесть названия полей для фильтров и адаптировать их под свои названия в коде.
код JS
// функция для генерации <option> элементов и их добавление в соответствующий <select>
const initOptions = (data, selectElement) => {
for (let item of data) {
const option = document.createElement('option');
option.value = item;
option.innerHTML = item;
selectElement.appendChild(option);
}
}
// объект для маппинга регион-достопримечательность
const regionAttrMap = {}
// обработка фильтрации достопримечательностей
const attrFilter = document.querySelector('.attr-filter');
attrFilter.addEventListener('change', (e) => {
setFilter('att_name', e.target.value, '=');
})
// обработка фильтрации регионов
const regionFilter = document.querySelector('.region-filter');
regionFilter.addEventListener('change', (e) => {
attrFilter.innerHTML = '';
initOptions(regionAttrMap[e.target.value], attrFilter);
setFilter('region', e.target.value, '=');
setFilter('att_name', '', '=');
})
// замыкание, чтобы фильтры заполнились только 1 раз при первом рендере
let init = true;
function render() {
// заполняем начальное состояние фильтров
if (init) {
// уникальные значения для фильтра по региону
let regions = DATA.data.map(item => item.region.value).filter(x => x);
regions = Array.from(new Set(regions));
// уникальные значения для фильтра по достопримечательностям
let attrs = DATA.data.map(item => item.att_name.value).filter(x => x);
attrs = Array.from(new Set(attrs));
// инициализация <option>
initOptions(regions, regionFilter);
initOptions(attrs, attrFilter);
// генерация маппинга регион-достопримечательность
DATA.data.reduce((acc, val) => {
if (!acc[val.region.value]) {
acc[val.region.value] = [];
} else {
acc[val.region.value].push(val.att_name.value);
}
return acc;
}, regionAttrMap)
for (let key in regionAttrMap) {
regionAttrMap[key] = Array.from(new Set(regionAttrMap[key])).filter(x => x)
}
init = false;
}
}
В результате получаем рабочий вариант взаимозависимых фильтров. При выборе региона в соседнем фильтре будут доступны только варианты, относящиеся к этому региону. Затем науровне дашборда можно настроить связь виджета HTML и любого другого по полю из фильтра.