Hi there, while dealing with tabular data (in this post we
are going to talk about material table), we must have to provide search
functionality to the user otherwise the user might get frustrated to find the intended
record. But mostly we provide a common search text box and that it will search for data
in the hole table and most importantly in all columns, what if the user wants to
search a value in a particular column. So here we are going to see how to add custom filters in the angular material table and very important is, we are not going to install any third-party
library.
Angular material table already provided you with filter
predicates and all, so you might get both codes, for common search and custom
search but, they are not going to work with each other. So here we are going to
solve this, in this post we are going to implement custom search/filter and
common search/filter and they are going to be work with each other. Let us do
it.
[If you have any problem related to the Angular material table please check our following posts:
Click here for a simple material table with searching, sorting, and pagination,
Click here for inline editing and validation with template-driven forms in the angular material table,
Click here for multiple expandable rows in the angular material table,
Click here for a table inside a row and multiple paginators in the angular material table,
Click here for a hide/show columns dynamically in the angular material table]
[If you have any problem related to the Angular material table please check our following posts:
Click here for a simple material table with searching, sorting, and pagination,
Click here for inline editing and validation with template-driven forms in the angular material table,
Click here for multiple expandable rows in the angular material table,
Click here for a table inside a row and multiple paginators in the angular material table,
Click here for a hide/show columns dynamically in the angular material table]
following is the HTML file of our angular component, in this, we have
added an angular material table with some data. Above the table we have added one
text box for common search and added pop up menu to add multiple custom filters,
both have a search button to search the entered value.
In custom filter, we have added drop-down to select, in which column we
want to search and added a clear button to clear all columns.
<div class="row">
<div class="col-12 text-center">
<label for="Heading" class="form-control">
Angular - Custom filter or search and common search together in Angular Material Table
</label>
</div>
</div>
<div class="row justify-content-center">
<div class="col-8">
<div class="example-container mat-elevation-z8">
<div class="col-12 text-right">
<button class="btn btn-sm btn-secondary ml-5" [matMenuTriggerFor]="filterBy">Custom filter</button>
<mat-menu #filterBy="matMenu">
<div (click)="$event.stopPropagation()">
<div *ngFor="let filter of customFilters">
<span class="ml-1">
{{filter.column}}
</span>
<span class="ml-1 mr-1">like</span>
<span>
<input class="form-control-sm ml-1 mr-1" type="text" placeholder="Search for" style="max-width: 150px;"
[(ngModel)]="filter.value">
</span>
</div>
<span>
<button class="btn btn-sm btn-light ml-2" *ngIf="!addFilterFlag" mat-raised-button
(click)="$event.stopPropagation(); addFilterFlag = true" title=" Add Filter">
<i class="fa fa-plus-square" aria-hidden="true"></i> Add Filter
</button>
<div *ngIf="addFilterFlag">
<select class="ml-2" [(ngModel)]="selectedCustomColumn">
<ng-container *ngFor="let column of displayedColumns">
<option value="null" disabled hidden></option>
<option *ngIf="ifExists(column)" [value]="column">{{column}}</option>
</ng-container>
</select>
<button class="btn btn-sm btn-light ml-2 mr-2"
(click)="addFilter(selectedCustomColumn);addFilterFlag = false">Add</button>
</div>
<button class="btn btn-sm btn-primary ml-2" (click)="customSearch()">Search</button>
<button class="btn btn-sm btn-primary ml-2 mr-2" (click)="clearCustomFilter()">Clear</button>
</span>
</div>
</mat-menu>
<input class="form-control-sm ml-2" type="text" #inp>
<button class="btn btn-sm btn-primary ml-1" (click)="applyFilter(inp.value)">Search</button>
<button class="btn btn-sm btn-primary ml-2 mr-2" (click)="clearCommonFilter(inp)">Clear</button>
</div>
<mat-table #table [dataSource]="dataSource" multiTemplateDataRows>
<!-- Roll No Column -->
<ng-container matColumnDef="rollNo">
<mat-header-cell *matHeaderCellDef> Roll No </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.rollNo}} </mat-cell>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.name}} </mat-cell>
</ng-container>
<!-- Marks Column -->
<ng-container matColumnDef="marks">
<mat-header-cell *matHeaderCellDef> Marks </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.marks}} </mat-cell>
</ng-container>
<!-- Standard Column -->
<ng-container matColumnDef="standard">
<mat-header-cell *matHeaderCellDef> Standard </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.standard}} </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;" matRipple class="element-row"></mat-row>
</mat-table>
</div>
</div>
</div>
After HTML let’s see the typescript file. Here we have declared
student interface to define the structure of the data then we have assigned
data because we are not making a call to the server, you can make a call
to the server, if you wish.
After that, for normal common filter/search, we had used a filter of the material table. It is very easy; we are only setting the filter value
everything else is taken care of by the material table.
Now for custom filter/search, we have
taken a “customFilters” array which holds column name and value to
search, when we add a custom filter in pop up, we push each column and its search
value in the above array and when user click the search button, we compare all given
columns and their filter values in our data, we filter that data based upon
given search value of a column and assign it to the data source.
The following code will make you understand everything.
import { Component } from '@angular/core';
import { MatTableDataSource } from '@angular/material';
export interface Student {
rollNo: number;
name: string;
marks: number;
standard: string;
}
const data: Student[] = [
{ rollNo: 1, name: 'Ramesh', marks: 78, standard: '10' },
{ rollNo: 2, name: 'Suresh', marks: 56, standard: '12' },
{ rollNo: 3, name: 'Adi', marks: 77, standard: '7' },
{ rollNo: 4, name: 'Rina', marks: 57, standard: '9' },
{ rollNo: 5, name: 'Tapil', marks: 66, standard: '9' },
{ rollNo: 6, name: 'Sugul', marks: 88, standard: '5' },
{ rollNo: 7, name: 'Aftar', marks: 46, standard: '5' },
{ rollNo: 8, name: 'Oxa', marks: 57, standard: '5' },
{ rollNo: 9, name: 'Tam', marks: 76, standard: '5' },
{ rollNo: 10, name: 'Luis', marks: 87, standard: '7' }
];
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent {
addFilterFlag = false;
selectedCustomColumn;
displayedColumns = ['rollNo', 'name', 'marks', 'standard'];
customFilters = [];
groupByColumns = [];
dataSource = new MatTableDataSource<Student>();
constructor() {
this.dataSource.data = data;
}
addFilter(columnName) {
this.customFilters.push({ column: columnName, value: '' });
this.selectedCustomColumn = null;
}
ifExists(columnName) {
for (const iterator of this.customFilters) {
if (iterator.column == columnName) {
return false;
}
}
return true;
}
customSearch() {
this.dataSource.data = data.filter(row => this.multipleFilterPredicate(row));
this.dataSource._updateChangeSubscription();
}
applyFilter(filterValue: string) {
filterValue = filterValue.trim();
filterValue = filterValue.toLowerCase();
this.dataSource.filter = filterValue;
}
multipleFilterPredicate(row) {
for (const iterator of this.customFilters) {
if (iterator.value != '' && (row[iterator.column] + '').toLocaleLowerCase().indexOf(iterator.value) == -1) {
return false;
}
}
return true;
}
clearCustomFilter() {
this.customFilters = [];
this.dataSource.data = data;
this.dataSource._updateChangeSubscription();
}
clearCommonFilter(inp) {
this.dataSource.filter = undefined;
inp.value = '';
}
}
We have not imported anything out of the angular library, here is the
module file.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule } from '@angular/forms';
import { DatePipe } from '@angular/common';
import {
MatMenuModule,
MatTableModule,
MatSlideToggleModule,
MatSelectModule
} from '@angular/material';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
FormsModule,
MatMenuModule,
MatTableModule,
MatSlideToggleModule,
MatSelectModule
],
providers: [DatePipe],
bootstrap: [AppComponent]
})
export class AppModule { }
Output
And that’s it,
Hope you like it.
Here you can download the project (click here)
When you download the project, at the very first run command “npm
install”.
Because of the size issue, we are not going to upload the node module folder
onwards.
Column filter is not working for me
ReplyDeletecheck customSearch() and multipleFilterPredicate(row) methods
Delete