Custom filter/search and common filter/search in angular material table


  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]



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 {
  rollNonumber;
  namestring;
  marksnumber;
  standardstring;
}

const dataStudent[] = [
  { rollNo: 1name: 'Ramesh'marks: 78standard: '10' },
  { rollNo: 2name: 'Suresh'marks: 56standard: '12' },
  { rollNo: 3name: 'Adi'marks: 77standard: '7' },
  { rollNo: 4name: 'Rina'marks: 57standard: '9' },
  { rollNo: 5name: 'Tapil'marks: 66standard: '9' },
  { rollNo: 6name: 'Sugul'marks: 88standard: '5' },
  { rollNo: 7name: 'Aftar'marks: 46standard: '5' },
  { rollNo: 8name: 'Oxa'marks: 57standard: '5' },
  { rollNo: 9name: 'Tam'marks: 76standard: '5' },
  { rollNo: 10name: 'Luis'marks: 87standard: '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: columnNamevalue: '' });
    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(filterValuestring) {
    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.


Comments

  1. Column filter is not working for me

    ReplyDelete
    Replies
    1. check customSearch() and multipleFilterPredicate(row) methods

      Delete

Post a Comment