Angular Material 9/8 DataTables, Pagination, Sorting, Filter & Fixed Columns Tutorial

Angular Material is a Material Design based UI library which provides a number of easy to use UI components. Angular Material data tables are used to display data in tabular format on pages.

In this tutorial, we will create a new Angular project using Angular CLI. Then we will install the Material library in an Angular project.

After application setup with Material, we will learn how to add Datatables and its important features like Pagination, column sorting, data filter and fixed sections on the table including headers and rows.

Let’s get started…

# Setup Angular CLI

We’ll create Angula project in the latest version. Make sure you have updated the Angular CLI tool by running below npm command in the terminal

$ npm install -g @angular/cli

 

# Create an Angular Project

Execute below ng command to create an Angular project in latest version 9.1.3. But this tutorial is compatible with previous version 7,6,5 and 4

$ ng new angular-material-checkboxlist
$ cd angular-material-checkboxlist

# Install Angular Material in project

After version 8, Angular Material package can be installed by executing the following ng command. For configuration, it will ask a few questions related to the theme, browser animations etc

$ ng add @angular/material

Answer questions

? Choose a prebuilt theme name, or "custom" for a custom theme: Indigo/Pink
? Set up global Angular Material typography styles? Yes
? Set up browser animations for Angular Material? Yes

We are done with Angular material installation and configurations. Now our Angular project is ready to use Material components.

 

# Import Material Modules

The Material UI library provides a wide variety of components, so we need to import the API module of the component we are going to use in the App module.

After adding Angular material in our project, next, we need to import MatTableModule  and MatSortModule for sorting in the datatable in the app.module.ts then add in imports array as shown below.

// app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { MatTableModule } from '@angular/material/table';
import { MatSortModule } from '@angular/material/sort';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,

    MatTableModule,
    MatSortModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Now we can use Material Datatables in our application.

#Create Simple Datatable

Let's start by adding the simplest Datatable in our App component.

Open app.component.ts file then add <table mat-table></table> Or <mat-table></mat-table> as datatable wrapper.

After that, we define a dataSource attribute with a data object.

<mat-table [dataSource]="dataSource">

</mat-table>

 

Define columns: Columns of data tables are defined by using the following template.

<ng-container matColumnDef="userName">
  <mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
  <mat-cell *matCellDef="let user"> {{user.name}} </mat-cell>
</ng-container>

 

The <ng-container> is to define column definition having matColumnDef value which must be unique for a column.

<mat-header-cell> with *matHeaderCellDef contains the Text for column header.

<mat-cell> having object key of data passed as variable in *matCellDef

After that in <mat-table> we add following templates for Header and Row cell configuration

    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
    <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>

displayedColumns will have an array list of columns we want to display in Datatables

displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];

 

Finally, our Simple Datatable will have the following template and component code.

<!-- app.component.html -->

  <mat-table [dataSource]="dataSource" class="mat-elevation-z8">

    <!--- Note that these columns can be defined in any order.
          The actual rendered columns are set as a property on the row definition" -->
  
    <!-- Position Column -->
    <ng-container matColumnDef="position">
      <mat-header-cell *matHeaderCellDef> No. </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.position}} </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>
  
    <!-- Weight Column -->
    <ng-container matColumnDef="weight">
      <mat-header-cell *matHeaderCellDef> Weight </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.weight}} </mat-cell>
    </ng-container>
  
    <!-- Symbol Column -->
    <ng-container matColumnDef="symbol">
      <mat-header-cell *matHeaderCellDef> Symbol </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.symbol}} </mat-cell>
    </ng-container>
  
    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
    <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
  </mat-table>

 

Also, update the component class as shown below

//app.component.ts

import { Component } from '@angular/core';


export interface PeriodicElement {
  name: string;
  position: number;
  weight: number;
  symbol: string;
}

const ELEMENT_DATA: PeriodicElement[] = [
  {position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H'},
  {position: 2, name: 'Helium', weight: 4.0026, symbol: 'He'},
  {position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li'},
  {position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be'},
  {position: 5, name: 'Boron', weight: 10.811, symbol: 'B'},
  {position: 6, name: 'Carbon', weight: 12.0107, symbol: 'C'},
  {position: 7, name: 'Nitrogen', weight: 14.0067, symbol: 'N'},
  {position: 8, name: 'Oxygen', weight: 15.9994, symbol: 'O'},
  {position: 9, name: 'Fluorine', weight: 18.9984, symbol: 'F'},
  {position: 10, name: 'Neon', weight: 20.1797, symbol: 'Ne'},
];


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent  {

  displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
  dataSource = ELEMENT_DATA;

}

# Pagination in Datatables

To add pagination in the datatable we need to import MatPaginatorModule in the app.module.ts file then add in the imports array

Then add <mat-paginator> immediately after <mat-table> tag as shown below

<!-- app.component.html -->

<mat-table [dataSource]="dataSource" class="mat-elevation-z8">
  <ng-container matColumnDef="position">
    <mat-header-cell *matHeaderCellDef> No. </mat-header-cell>
    <mat-cell *matCellDef="let element"> {{ element.position }} </mat-cell>
  </ng-container>

  <ng-container matColumnDef="name">
    <mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
    <mat-cell *matCellDef="let element"> {{ element.name }} </mat-cell>
  </ng-container>

  <ng-container matColumnDef="weight">
    <mat-header-cell *matHeaderCellDef> Weight </mat-header-cell>
    <mat-cell *matCellDef="let element"> {{ element.weight }} </mat-cell>
  </ng-container>

  <ng-container matColumnDef="symbol">
    <mat-header-cell *matHeaderCellDef> Symbol </mat-header-cell>
    <mat-cell *matCellDef="let element"> {{ element.symbol }} </mat-cell>
  </ng-container>

  <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
  <mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-paginator
  [pageSizeOptions]="[5, 10, 20]"
  showFirstLastButtons
></mat-paginator>

 

In the app.componet.ts file, we will import MatPaginator & MatTableDataSource and use it to get paginator instance as shown below

//app.component.ts

import { Component, ViewChild } from '@angular/core';

import { MatPaginator, MatTableDataSource } from '@angular/material';


export interface PeriodicElement {
  name: string;
  position: number;
  weight: number;
  symbol: string;
}

const ELEMENT_DATA: PeriodicElement[] = [
  { position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H' },
  { position: 2, name: 'Helium', weight: 4.0026, symbol: 'He' },
  { position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li' },
  { position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be' },
  { position: 5, name: 'Boron', weight: 10.811, symbol: 'B' },
  { position: 6, name: 'Carbon', weight: 12.0107, symbol: 'C' },
  { position: 7, name: 'Nitrogen', weight: 14.0067, symbol: 'N' },
  { position: 8, name: 'Oxygen', weight: 15.9994, symbol: 'O' },
  { position: 9, name: 'Fluorine', weight: 18.9984, symbol: 'F' },
  { position: 10, name: 'Neon', weight: 20.1797, symbol: 'Ne' },
];


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
  dataSource = new MatTableDataSource<PeriodicElement>(ELEMENT_DATA);
  @ViewChild(MatPaginator) paginator: MatPaginator;

  ngOnInit() {
    this.dataSource.paginator = this.paginator;
  }

}

 

# Sorting on Datatable Columns

After that add matSort directive on mat-table wrapper then mat-sort-header on every column where you want sorting functionality.

<mat-table [dataSource]="dataSource" class="mat-elevation-z8" matSort>
  <ng-container matColumnDef="position">
    <mat-header-cell *matHeaderCellDef  mat-sort-header> No. </mat-header-cell>
    <mat-cell *matCellDef="let element"> {{ element.position }} </mat-cell>
  </ng-container>
...
...

In the app.componet.ts file in which we have Datatable, we will import MatSort then use that instance as shown below

//app.component.ts

import { Component, ViewChild } from '@angular/core';

import { 
  MatSort, 
  MatPaginator, 
  MatTableDataSource } from '@angular/material';


export interface PeriodicElement {
  name: string;
  position: number;
  weight: number;
  symbol: string;
}

const ELEMENT_DATA: PeriodicElement[] = [
  { position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H' },
  { position: 2, name: 'Helium', weight: 4.0026, symbol: 'He' },
  { position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li' },
  { position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be' },
  { position: 5, name: 'Boron', weight: 10.811, symbol: 'B' },
  { position: 6, name: 'Carbon', weight: 12.0107, symbol: 'C' },
  { position: 7, name: 'Nitrogen', weight: 14.0067, symbol: 'N' },
  { position: 8, name: 'Oxygen', weight: 15.9994, symbol: 'O' },
  { position: 9, name: 'Fluorine', weight: 18.9984, symbol: 'F' },
  { position: 10, name: 'Neon', weight: 20.1797, symbol: 'Ne' },
];


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
  dataSource = new MatTableDataSource<PeriodicElement>(ELEMENT_DATA);
  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;

  ngOnInit() {
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;
  }

}

 

# Filter Datatable Rows

To filter datatable rows we will add an input field with a (keyup) event listener, which will simply filter the dataSource object as shown below

<mat-form-field>
  <input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
</mat-form-field>

In app.component.ts file just add below method to filter datatable data.

....
....

  applyFilter(filterValue: string) {
    this.dataSource.filter = filterValue.trim().toLowerCase();
  }

# Sticky or Freeze Headers and Columns in Datatables

Sometime we may need to freeze Header or Footer rows or Columns with Checkboxes or actions. We can use sticky directive on our Headers, Footers or Columns as shown below.

Freeze Header:

<mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></mat-header-row>

Freeze Footer: 

<mat-footer-row *matFooterRowDef="displayedColumns; sticky: true"></mat-footer-row>

Freeze Columns:

    <ng-container matColumnDef="name" sticky>
      <mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.name}} </mat-cell>
    </ng-container>

 

So here we quickly go through some powerful features available in Angular Material Datatables, you can check more details on docs here.

Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments