Я — начинающий front-end разработчик. Сейчас я учусь и стажируюсь в одной минской IT компании. Изучение основ web-ui проходит на примере JS библиотеки Webix. Я хочу поделиться своим скромным опытом и сохранить его в виде небольшого учебного пособия по этой интересной UI библиотеке.
ПЯТАЯ ЗАДАЧА
В прошлой статье, Работа с данными, на основе функций CRUD я писал о стандартных задачах по управлению данными приложения. На этом этапе я попытаюсь сделать приложение более дружественным для пользователя и реализую возможность фильтровать, сортировать и группировать данные. В статье я рассмотрю следующие задачи:
- фильтрация и сортировка данных таблицы;
- фильтрация и сортировка через API;
- группировка данных древовидной таблицы;
- синхронизация компонентов;
В документации можно ознакомиться с использованными в статье виджетами List, Treetable, Table.
Исходники находятся по ссылке.
С готовым приложением можно ознакомиться тут.
Фильтрация и сортировка данных таблицы
Начнем с таблиц — их я чаще всего использовал для работы с большим количеством данных. Таблицы в библиотеке Webix имеют ряд встроенных фильтров, которые устанавливаются прямо в header виджетов Table и TreeTable. В виджете Table я использую два варианта: простой текстовый фильтр (textFilter) и фильтр с набором опций в выпадающем списке (selectFilter). Таблица позволяет добавить по одному фильтру для каждой колонки. Сделаю это для двух: title и year. Header в них вместо строки задам массивом — чтобы уместить заголовок и фильтр. Второй элемент массива, это объект со свойством content и именем фильтра.
Код виджета Table находится в файле table.js и отрисован во вкладке “Dashboard”.
При вводе символов в
"textFilter"
данные будут отфильтрованы совпадением по подстроке. При выборе опции в "selectFilter"
— по выбранному значению.columns:[
{ id:"rank", header:"", width:50, css:"rank"},
{ id:"title", header:["Film title", { content:"textFilter"}], fillspace:true },
{ id:"year", header:["Released", {content:"selectFilter" }], width:100 },
{ id:"votes", header:"Votes", width:100 },
{ id:"rating", header:"Rating", width:100 },
{ header:"", template:"<span class='webix_icon wxi-close'></span>", width:35}
]
Результат фильтрации по подстроке “star”:
Результат фильтрации элементов по выбранному значению “1991”:
Сортировка. Как и в случае с фильтрами, сортировку так же легко сделать доступной для пользователя. Для этого достаточно дополнить конфигурацию колонок свойством sort. Есть несколько готовых типов сортировки: по числовым значениям, по дате и по строке. Столбцам year, votes и rating я установлю настройку sort: “int” для сортировки по числовым значениям. Для столбца title значение будет “string”.
columns:[
{ id:"rank", header:"", width:50, css:"rank"},
{ id:"title", header:["Film title", { content:"textFilter"}], fillspace:true,
sort:"string"},
{ id:"year", header:["Released", {content:"selectFilter" }], width:100, sort:"int"},
{ id:"votes", header:"Votes", width:100, sort:"int"},
{ id:"rating", header:"Rating", width:100, sort:"int"},
{ header:"", template:"<span class='webix_icon wxi-close'></span>", width:35}
]
По клику на header колонки данные будут отсортированы в соответствии с их типом. Результат сортировки по рейтингу:
Сортировка и фильтрация через API
Готовые решения для фильтрации и сортировке элементов имеют только таблицы. Но в целом все виджеты поддерживают эти возможности через соответствующие методы API — filter и sort. Фильтрацию и сортировку при помощи API я продемонстрирую у виджета List.
Код виджета List находится в файле users_module.js и отрисован во вкладке “Users”.
Фильтрация. Во вкладке Users, после кнопки “Add new person”, я установлю виджет Text, который использую в качестве фильтра для имен из списка.
cols:[
{
view:"button", id:"btn_add_person",
value:"Add new person", width:150, css:"webix_primary",
click:addPerson
},
{
view:"text", id:"list_input"
},
]
Теперь открою файл script.js и добавлю логику отвечающую за фильтрацию элементов.
$$("list_input").attachEvent("onTimedKeyPress",function(){
var value = this.getValue().toLowerCase();
$$("user_list").filter(function(obj){
return obj.name.toLowerCase().indexOf(value) !== -1;
})
});
Фильтрация элементов происходит по такому принципу:
- при помощи метода attachEvent я добавляю обработчик на событие onTimedKeyPress;
- событие onTimedKeyPress вызывается вводом символов в текстовое поле, но с короткой задержкой, чтобы не задействовать фильтр при каждом нажатии клавиш;
- далее я получаю введенный текст и методом filter запускаю фильтрацию — поиск совпадений в виджете List.
Результат фильтрации через API:
Сортировка. Сортировка элементов виджета List будет происходить по клику кнопок
“Sort asc”
и “Sort desc”
. Чтобы создать кнопки во вкладке Users, после текстового поля я добавлю два виджета Button с обработчиком событий click.
cols:[
{
view:"button", id:"btn_add_person",
value:"Add new person", width:150, css:"webix_primary",
click:addPerson
},
{
view:"text", id:"list_input"
},
{ view:"button", id:"btn_asc", width:150, value:"Sort asc", css:"webix_primary",
click:()=>{
$$("user_list").sort("#name#","asc")
}},
{ view:"button", id:"btn_desc", width:150, value:"Sort desc", css:"webix_primary",
click:()=>{
$$("user_list").sort("#name#","desc")
}},
]
Внутри обработчика click, метод sort принимает для параметра: имя поля, по которому сортируем данные, и направление сортировки
“asc”
(ascending) — по возрастанию, и “desc”
(descending) — по убыванию. По умолчанию данные считаются строками и сортируются соответствующим образом.Результат (имена в листе отсортированы по алфавиту):
Группировка данных древовидной таблицы
Рассмотрим ситуацию когда данные надо сгруппировать по произвольным параметрам.
Изучать группировку я буду на примере виджета TreeTable.
Код виджета TreeTable находится в файле products_module.js и отрисован во вкладке “Poducts”.
В статье: Модули, диаграммы, древовидные таблицы и Работа с данными. CRUD, в древовидной таблице я использовал иерархические данные. Для решения этой задачи я их изменил, чтобы получить линейный массив. Я избавился от иерархии и перенес из нее в каждую запись поле
“category”
.[
{"id": "1.1", "title": "Standard Ticket", "price": 21, "category":"Cinema", "rank":1.1},
{"id": "2.1", "title": "Cola", "price": 10, "category":"Cafe", "rank":2.1},
{"id": "3.1", "title": "Flowers", "price": 10, "category":"Other", "rank":3.1}
]
Сгруппировать данные в таблице можно двумя способами:
Параметры у этих методов одинаковые и мне нужно сгруппировать данные один раз, как только они пришли, поэтому я использую первый вариант.
В конфигурации виджета TreeTable добавлю свойство scheme. Это свойство определяет по какой схеме будут обработаны данные в разных ситуациях. Среди обработчиков в sheme есть метод $group, который мне нужен для группировки данных.
const products = {
editable:true,
view:"treetable",
scrollX:false,
columns:[
{ id:"rank", header:"", width:50 },
{ id:"title", header:"Title", fillspace:true, template:"{common.treetable()} #title#"},
{ id:"price", header:"Price", width:200, editor:"text" }
],
select:"row",
url:"data/products.js",
scheme:{
$group:{
by:"category",
map:{
title:["category"]
}
},
$sort:{ by:"value", dir:"asc" }
}
}
Внутри обработчика $group использовано два параметра:
- обязательный параметр by, по которому группируются данные. Здесь — одно из полей (“category”);
- объект map — здесь опишем поля данных для создаваемых групп. Группировка разбивает исходные данные по указанным параметрам и создает для них «родительские записи». Через map мы можем добавить в эти записи новые поля. Чтобы данные в таблице отображались корректно, добавлю поле “title”. Передам в него значение параметра, по которому происходит группировка.
Дополнительно я установил функцию $sort, чтобы отсортировать сгруппированные данные в алфавитном порядке.
Результат группировки:
Синхронизация компонентов
В задаче использованы виджеты Chart и List, код которых в файле users_module.js и отрисованы во вкладке “Users”
Виджеты Chart и List используют одни и те же данные — массив JSON. Эти компоненты можно связать так, чтобы все изменения данных в одном из них (источнике) транслировались в другой. Для этого используется метод sync.
Метод sync позволяет копировать данные из одного компонента и передавать их другому. При этом, изменения в основном компоненте, такие как добавление, удаление, и пр., сразу отражаются в другом.
Для начала, в виджете Chart — диаграмма — я удалю ссылку на данные.
{
view:"chart",
id:"chart",
type:"bar",
value:"#age#",
label:"#age#",
xAxis:{
template:"#name#",
title:"Age"
}
}
Теперь, в файле script.js методом sync я синхронизирую виджет Chart с виджетом List.
$$("chart").sync($$("user_list"));
В функции addPerson добавление оставляем только для виджета List.
let addPerson = () => {
let obj = {
name:"Some name",
age:Math.floor(Math.random() * 80) + 10,
country:"Some country"
}
$$("user_list").add(obj);
};
Теперь при добавлении и удалении записей из списка, изменения будут происходить и в диаграмме. Сортировка и фильтрация в виджете List теперь затронет и данные в Chart.
Обобщение
На практических примерах я показал как можно улучшить работу пользователя. Помимо стандартной сортировки и фильтрации при помощи API была освоена встроенная возможность сделать это в виджетах Table и TreeTable одной настройкой. Был продемонстрирован способ группировки данных в таблице, а пример синхронизации расширил возможность усовершенствовать работу виджетов, использующих один и тот же источник данных.
С готовым приложением можно ознакомиться тут.