Learn how to allow data interactions sorting, filtering, grouping and aggregating more effectively with Kendo UI for Angular.
In the previous article, we explored how to allow data interactions sorting, filtering, grouping and aggregating by using built-in Array methods. While Array provides some native methods to handle these, they can fall short in flexibility, simplicity and overall effectiveness when dealing with complex data manipulation tasks.
Today we are going solve the same case but using the Progress Kendo UI for Angular Data Query, because it provides a robust and comprehensive solution to handle data operations more effectively.
The Kendo UI for Angular Data Query outshines native Array methods in several ways:
process
method from Kendo UI Data Query allows for a combination of sorting, filtering, grouping and aggregating data in a single operation, providing an efficient and compact way
to manipulate data.This article aims to illustrate the benefits and practical applications of Kendo UI Data Query in an Angular context by providing hands-on examples for each of these operations.
Let’s dive in!
We aim to optimize an existing body of code from a previous article focused on data manipulation in Angular. The goal is to refactor this code, making it more flexible, easier to comprehend and less complex for other developers to handle.
Previously, we worked with a list of products, implementing common data manipulation.
Now, we aim to streamline this scenario by implementing Kendo UI for Angular Data Query to solve each case:
The idea is to improve the readability and maintainability of the resulting code, facilitating a smoother development experience.
First, clone the repository:
C:\Users\INNO-IT\Desktop\lab>git clone https://github.com/danywalls/angular-play-with-data
Cloning into 'angular-play-with-data'...
remote: Enumerating objects: 52, done.
remote: Counting objects: 100% (52/52), done.
remote: Compressing objects: 100% (44/44), done.
Receiving objects: 65% (34/52)used 42 (delta 5), pack-reused 0
Receiving objects: 100% (52/52), 194.98 KiB | 2.07 MiB/s, done.
Resolving deltas: 100% (15/15), done.
Next, restore all packages using npm i
. Next add the Kendo UI Data Query package to our project. Run the following command in your project root:
PS C:\Users\INNO-IT\Desktop\angular-play-with-data-master> npm install --save @progress/kendo-data-query
added 2 packages, and audited 886 packages in 2s
After successful installation, we can import any function from the Kendo UI Data Query package in the app.component.ts file. Let’s move on to the first operation.
When we use the array methods, data sorting is typically achieved using the native sort function, like the following code snippet:
this.products = this.products.sort((a, b) => a.price - b.price);
this.products = this.products.sort((a, b) => b.price - a.price);
It may not be clear which operation sorts in ascending or descending order. While this can be resolved with comments or further documentation, adding this is an extra step that often goes overlooked.
This is where Kendo UI Data Query comes in with its orderBy
method. This method offers several significant advantages over the native sort function.
Firstly, the orderBy
method provides a more straightforward, declarative syntax for defining sorting criteria, which enhances readability. Furthermore, it respects data immutability—a key concept in frameworks like
Angular—ensuring that the original data array is not altered by the sorting operation.
Here’s how you can use the orderBy
method:
import { orderBy, SortDescriptor } from '@progress/kendo-data-query';
sortDescriptor: SortDescriptor = {field: 'price', dir: 'asc'};
public sortProductsAsc(): void {
this.sortDescriptor.dir = 'asc';
this.products = orderBy(this.products, [this.sortDescriptor]);
}
public sortProductsDesc(): void {
this.sortDescriptor.dir = 'desc';
this.products = orderBy(this.products, [this.sortDescriptor]);
}
In the above code, the orderBy
function is used to sort the data. It requires two parameters: the data array and an array of SortDescriptor objects. Each SortDescriptor
outlines the field
by which we want to sort and the sorting direction (dir
).
By implementing Kendo UI Data Query’s orderBy
function, we have created code that is clearer for both senior and junior developers, saving time and improving maintainability.
Filtering data in JavaScript is often accomplished through the filter
method, like the following code:
this.products = this.products.filter(p => p.name === nameInput.value)
While this code snippet is reasonably straightforward, providing a match where the product name equals the input value, it quickly becomes complex if you wish to implement more advanced filtering criteria such as:
To address these complexities, Kendo UI Data Query offers the filterBy
method, a more powerful and configurable alternative to the array filter method. This feature enables complex filter operations and nested filtering,
all with an easy-to-use API.
Instead of writing a complex arrow function with the filtering logic, we use the filterBy
function. This function accepts a FilterDescriptor
object, which provides a clearer API and enhanced
readability.
Here’s how we can implement it:
import { FilterDescriptor, filterBy, FilterOperator
} from '@progress/kendo-data-query';
filterDescriptor: FilterDescriptor = {field: 'name', operator: FilterOperator.EqualTo, value: '', };
filterProducts(nameInput: HTMLInputElement) {
if (nameInput.value) {
this.filterDescriptor.value = nameInput.value;
this.products = filterBy(this.products, this.filterDescriptor);
}
}
With Kendo UI Data Query filterBy
function, you can construct advanced filtering scenarios in a straightforward, readable manner—resulting in cleaner and more maintainable code.
Grouping data using native JavaScript often involves complex loop structures and additional code, which can potentially complicate your application. Take, for instance, the code below that groups products by category:
//first group the products by category
const grouped = this.products.reduce((acc: any, curr) => {
let key = curr.category;
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(curr);
return acc;
}, {});
//get the categories and product related.
this.categories = Object.keys(grouped).map(key => ({
category: key,
products: grouped[key]
}));
This approach works but is not quite intuitive and may become complex to maintain in a large codebase.
Kendo UI Data Query offers the groupBy
function, which greatly simplifies the process of grouping data. It provides a clear, declarative approach and requires only a simple array of GroupDescriptor
objects, making your code more readable and maintainable.
We could refactor the previous example to utilize groupBy
in this way:
import { groupBy, GroupDescriptor, process } from '@progress/kendo-data-query';
groupDescriptor: GroupDescriptor[] = [{field: 'category'}];
groupProducts() {
this.categories = process(this.products, {group: this.groupDescriptor}).data
}
In the refactored version, the groupBy
function takes care of the grouping operation using two parameters—the data array and an array of GroupDescriptor objects. Each GroupDescriptor
object specifies the field we want to group by.
This refactored version not only achieves the same result as the initial code but does so in a more intuitive and simplified way.
This demonstrates the power of Kendo UI Data Query in enhancing the clarity and maintainability of your Angular applications, especially when dealing with complex data manipulation tasks.
In JavaScript, we don’t have a real solution for data aggregation. Most developers use a reduce function like:
this.total = this.products.reduce((acc, curr) => acc + curr.price, 0);
While experienced developers might recognize this as a summation of product prices using the reduce function, the code isn’t readily clear or scalable for more complex scenarios such as aggregating multiple fields or calculating average, minimum or maximum values.
For these reasons, it is much more efficient and intuitive to use Kendo UI Data Query’s aggregateBy
function. This powerful function can perform complex calculations such as the sum, average, minimum, maximum or
count of specified fields—resulting in cleaner and more maintainable code.
The aggregateBy
function takes in two parameters: the data array and an array of AggregateDescriptor
objects. Each AggregateDescriptor
defines a field to
aggregate and the aggregation function to apply.
For instance, if we’re looking to find the sum of prices for all products, the code would look like this:
import { aggregateBy, AggregateDescriptor } from '@progress/kendo-data-query';
showTotal(){
// this.total = this.products.reduce((acc, curr) => acc + curr.price, 0);
let aggregates: AggregateDescriptor[] = [{field: "price", aggregate: "sum"}];
let result = aggregateBy(this.products, aggregates);
this.total = result['price'].sum;
}
The result is an object where each key is a field name, and the corresponding value is an object containing the calculated aggregate values.
In essence, the aggregateBy
function allows for straightforward and understandable data manipulation, which is particularly beneficial when handling complex data scenarios. Its utilization leads to more readable code,
promoting better maintenance and understanding for both junior and senior developers alike. Plus, it’s just good clean fun! ;)
We’ve discovered the power and simplicity of using Kendo UI Data Query for data manipulation in Angular applications, helping us to create easily maintainable and highly predictable code.
Kendo UI Data Query handles data-related operations such as sorting, filtering, grouping and aggregation, all while respecting data immutability.
I recommend checking out the official Kendo UI documentation, which offers great examples of how to
do amazing things with Kendo UI Data Query.
And if you haven’t already, you can try Kendo UI for Angular today for free!
Dany Paredes is a Google Developer Expert on Angular and Progress Champion. He loves sharing content and writing articles about Angular, TypeScript and testing on his blog and on Twitter (@danywalls).