JavaScript библиотека Webix глазами новичка. Часть 5. Работа с данными на стороне пользователя

от автора

Я — начинающий front-end разработчик. Сейчас я учусь и стажируюсь в одной минской IT компании. Изучение основ web-ui проходит на примере JS библиотеки Webix. Я хочу поделиться своим скромным опытом и сохранить его в виде небольшого учебного пособия по этой интересной UI библиотеке.

ПЯТАЯ ЗАДАЧА

В прошлой статье, Работа с данными, на основе функций CRUD я писал о стандартных задачах по управлению данными приложения. На этом этапе я попытаюсь сделать приложение более дружественным для пользователя и реализую возможность фильтровать, сортировать и группировать данные. В статье я рассмотрю следующие задачи:

В документации можно ознакомиться с использованными в статье виджетами 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} ] 

Сгруппировать данные в таблице можно двумя способами:

  • сразу при их загрузке;
  • динамически, при помощи методов group и ungroup.

Параметры у этих методов одинаковые и мне нужно сгруппировать данные один раз, как только они пришли, поэтому я использую первый вариант.
В конфигурации виджета 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 одной настройкой. Был продемонстрирован способ группировки данных в таблице, а пример синхронизации расширил возможность усовершенствовать работу виджетов, использующих один и тот же источник данных.

С готовым приложением можно ознакомиться тут.

ссылка на оригинал статьи https://habr.com/ru/post/489024/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *