Mastering Data Filtering with Complex Objects: Strategies and Techniques
Hi Everyone, The filter logic is a mechanism that allows you to search and retrieve specific data from a larger dataset. The filter function takes two arguments: the data to filter and a filter parameter that defines the search criteria. The function returns a subset of the original data that matches the filter criteria.So lets understand how we can acheive "Data Filtering with Complex Objects".
In the case of the Angular Material table, the filter logic is used to search for specific data in a table by applying a search filter to one or more columns. When the user enters a search query, the filter logic is triggered and filters the table data based on the search criteria. The filtered data is then displayed in the table.
The filter logic can be implemented in many ways, depending on the specific use case.
Now consider this JSON array which contains nested array.
[
{
deviceUUID: ‘80a9b8a2–3a2c’,
ipAddress: ‘2.2.2.67’,
deviceParameter: {
deviceName: ‘device44’,
unitIdentifier: 1,
port: 502,
},
isConnected: false,
isSerial: false,
details: null,
Type: ‘Ethernet’,
},
{
deviceUUID: ‘80a9b8a2–3a2c’,
ipAddress: ‘2.2.2.67’,
deviceParameter: {
deviceName: ‘device46’,
unitIdentifier: 1,
port: 503,
},
isConnected: false,
isSerial: false,
details: null,
Type: ‘Ethernet’,
},
{
deviceUUID: ‘80a9b8a2–3a2c’,
ipAddress: ‘2.2.2.67’,
deviceParameter: {
deviceName: ‘device48’,
unitIdentifier: 1,
port: 505,
},
isConnected: false,
isSerial: false,
details: null,
Type: ‘Ethernet’,
}
];
So if our requirement says that filter the object on ‘device name’ or ‘port’ that is not quite possible because that mat-filter is works with straight forward object but we can also achieve this things first understand how we can do that
The inner object search is different because it requires accessing a nested property within each object of an array, whereas other searches involve searching for a property directly in each object of the array. This requires a different approach to extract the nested property and perform the search.
So here we use ‘ filterPredicate’ to search nested object : The filterPredicate is used to search nested objects in a mat-table because the default filter behaviour in Angular Material only works on flat objects with simple properties. When dealing with more complex data structures like nested objects, we need to write their own custom filtering logic to extract the nested data they want to filter on. The filterPredicate function provides a way to do this by allowing us to write own filtering logic based on the nested data structure of their data source.
So lets begin with our example.
first create a one project which have preinstall angular material and all dependencies that is required to run angular mat-table to run
2. Here is my app.component.html code to declare mat-table
<mat-label>Filter</mat-label>
<input matInput (keyup)=”applyFilter($event)” placeholder=”Ex. ium” #input>
<table mat-table [dataSource]=”dataSource” matSort matSortActive=”deviceName” matSortDirection=”asc” matSortDisableClear>
<ng-container matColumnDef=”deviceName”>
<th mat-header-cell *matHeaderCellDef mat-sort-header> Device Name </th>
<td mat-cell *matCellDef=”let device”> {{device.deviceParameter.deviceName}} </td>
</ng-container>
<ng-container matColumnDef=”unitIdentifier”>
<th mat-header-cell *matHeaderCellDef> Unit Identifier </th>
<td mat-cell *matCellDef=”let device”> {{device.deviceParameter.unitIdentifier}} </td>
</ng-container>
<ng-container matColumnDef=”port”>
<th mat-header-cell *matHeaderCellDef> Port </th>
<td mat-cell *matCellDef=”let device”> {{device.deviceParameter.port}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef=”displayedColumns”></tr>
<tr mat-row *matRowDef=”let row; columns: displayedColumns;”></tr>
</table>
3. Replace the component.ts code with this
import { Component } from ‘@angular/core’;
import { MatTableDataSource } from ‘@angular/material/table’;
export interface Device {
deviceUUID: string;
ipAddress: string;
deviceParameter: {
deviceName: string;
unitIdentifier: number;
port: number;
};
isConnected: boolean;
isSerial: boolean;
details: any;
Type: string;
}
const DEVICE_LIST: Device[] = [
{
deviceUUID: ‘80a9b8a2–3a2c’,
ipAddress: ‘2.2.2.67’,
deviceParameter: {
deviceName: ‘device44’,
unitIdentifier: 1,
port: 502,
},
isConnected: false,
isSerial: false,
details: null,
Type: ‘Ethernet’,
},
{
deviceUUID: ‘80a9b8a2–3a2c’,
ipAddress: ‘2.2.2.67’,
deviceParameter: {
deviceName: ‘device46’,
unitIdentifier: 1,
port: 503,
},
isConnected: false,
isSerial: false,
details: null,
Type: ‘Ethernet’,
},
{
deviceUUID: ‘80a9b8a2–3a2c’,
ipAddress: ‘2.2.2.67’,
deviceParameter: {
deviceName: ‘device48’,
unitIdentifier: 1,
port: 505,
},
isConnected: false,
isSerial: false,
details: null,
Type: ‘Ethernet’,
}
];
@Component({
selector: ‘app-root’,
templateUrl: ‘./app.component.html’,
styleUrls: [‘./app.component.css’]
})
export class AppComponent {
title = ‘MaterialDesign’;
displayedColumns: string[] = [‘deviceName’, ‘unitIdentifier’, ‘port’];
dataSource = new MatTableDataSource<Device>(DEVICE_LIST);
constructor() {
// this.dataSource = new MatTableDataSource<Device>(DEVICE_LIST);
this.dataSource.filterPredicate = (data: Device, filter: string) => {
const searchString = filter.trim().toLowerCase();
return data.deviceParameter.deviceName.toLowerCase().includes(searchString) ||
data.deviceParameter.port.toString().toLowerCase().includes(searchString);
};
}
applyFilter(event: Event) {
const filterValue=(event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}
}
4. Replace the app.module.ts file with following code :
import { NgModule } from ‘@angular/core’;
import { BrowserModule } from ‘@angular/platform-browser’;
import { AppRoutingModule } from ‘./app-routing.module’;
import { AppComponent } from ‘./app.component’;
import { BrowserAnimationsModule } from ‘@angular/platform-browser/animations’;
import { MatSlideToggleModule } from ‘@angular/material/slide-toggle’;
import { MatButtonModule } from ‘@angular/material/button’;
import { MatTableModule } from ‘@angular/material/table’;
import { MatPaginatorModule } from ‘@angular/material/paginator’;
import { MatSortModule } from ‘@angular/material/sort’;
import { MatFormFieldModule } from ‘@angular/material/form-field’;
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
MatSlideToggleModule,
MatButtonModule,
MatTableModule,
MatPaginatorModule,
MatSortModule,
MatFormFieldModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Now understand how this filterPredicate function works. please again review this code
constructor() {
this.dataSource.filterPredicate = (data: Device, filter: string) => {
const searchString = filter.trim().toLowerCase();
return data.deviceParameter.deviceName.toLowerCase().includes(searchString) ||
data.deviceParameter.port.toString().toLowerCase().includes(searchString);
};
}
applyFilter(event: Event) {
const filterValue=(event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}
The function is being assigned to the filterPredicate property of a MatTableDataSource object.
It takes two arguments: data and filter. data represents a single element in the data source, while filter is the value entered by the user to filter the data.
searchString is a variable that is created by trimming any whitespace and converting the filter string to lowercase.
The function returns a boolean value that determines whether or not the data object should be included in the filtered data source. It does this by checking if the lowercase deviceName or lowercase port of the deviceParameter object of the data object includes the searchString.
If the searchString is found in either deviceName or port, the function returns true, indicating that the data object should be included in the filtered data source.
If the searchString is not found in either deviceName or port, the function returns false, indicating that the data object should be excluded from the filtered data source.
Please feel free to check out my GitHub repository at the following link, where you can find the code for the NestedObjectFilterMatTable:
Filter Nested Complex object
I would greatly appreciate it if you could take a look at it and let me know if you have any feedback or suggestions. Thank you very much for your time and consideration.