Subscribe Us

Angular Material DataTable Implementation With Filter, Sort, Pagination Tutorial


Angular Material DataTable Implementation


Angular Material DataTable Implementation 

 Introduction


All right in this tutorial let's take a look at implementing a basic data table in angular material.

Description


The first step as always is to import the module so in material.module.ts import MatTableModule and added to the material array.


import { NgModule } from '@angular/core';
import
{
    MatButtonModule,
    MatButtonToggleModule,
    MatSnackBarModule,
    MatDialogModule,
    MatTableModule
}
from '@angular/material'

const MaterialComponents=
[   
    MatButtonModule,
    MatButtonToggleModule,
    MatSnackBarModule,
    MatDialogModule,
    MatTableModule   
];

@NgModule({
 imports: [MaterialComponents],
 exports: [MaterialComponents]
})
export class MaterialModule { }


Now what we are going to do to save us some time is to copy the code for a basic data table and then understand the different parts that are responsible for the functioning of a data table so go to the link
https://material.angular.io/components/table/examples.

In the material Doc's go to components and then to the data table section and click on the table link over here in the examples tab we have a basic data table now go to the second example which is the basic use of mat-table and uses display flex and click on the code icon.

Now let's copy-paste the code first the HTML so copy and paste it in app.component.html.

 <mat-table [dataSource]="dataSource" class="mat-elevation-z8">
  <!-- 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>


Next the typescript file so go to ts copy the interface and the data in app.component.ts paste it right after the import statement.

import { Component } from '@angular/core';
import {MatSnackBar} from '@angular/material'
import {MatDialog} from '@angular/material'
import { CustomSnackBarComponent } from './custom-snack-bar/custom-snack-bar.component';
import { DialogExampleComponent } from './dialog-example/dialog-example.component';

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.scss']
})
export class AppComponent {
  displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
  dataSource = ELEMENT_DATA;
  numbers=[];
  constructor(private snackBar: MatSnackBar, public dialog: MatDialog){
    for(let i=0; i<1000 ; i++){
      this.numbers.push(i);
    }
  }

  openSnackBar(message, dismiss){
    let snackBarRef=this.snackBar.open(message,dismiss, {duration:2000});
    snackBarRef.afterDismissed().subscribe(()=>{
      console.log('The snackbar was dismissed');
    });

    snackBarRef.onAction().subscribe(()=>{
      console.log('The snackbar action was triggered');
    });
  }

  openCustomSnackBar(){
    this.snackBar.openFromComponent(CustomSnackBarComponent, {duration:2000});
  }

  openDialog(){
    let dialogRef=this.dialog.open(DialogExampleComponent, {data: {name: 'Manoj'}});
    dialogRef.afterClosed().subscribe(result=>{
      console.log('Dialog result', result);
    })
  }
}


Then go back to the documentation and copy the two lines of code from the component class go back to css code and in app component paste them finally copy the CSS so we're here CSS and then copy this and paste it in app.component.css.

.number{
    display:flex;
    justify-content: center;
    align-items: center;
    border: 2px solid maroon;
    box-sizing: border-box;
    height:100px;
}

.container{
    height: 400px;
}

table {
    width: 100%;
  }

Now if we save all the files and take a look at the browser, you should be able to see a data table now.


 


Let's understand the different parts that make up this data table the first part in implementing a data table is the data source. Every data table needs a data source that contains the data to be displayed. In our example we have the data of periodic elements we have an interface that defines the type of each element so a periodic element will have a name position rate and symbol. Right below the interface is where you see the array of periodic elements we have ten elements each having properties mentioned in the interface what you have to notice here is that the interface and the data array is declared outside the component to be able to use it in the component we need to create a property and initialize it.

For that purpose we have a data source which is initialized to  element data. alright the next thing to do is to provide this data source to the data table and we do that in the HTML so in app.component.html we create a data table with mat-table component and to provide the data source they make use of the data source attribute. We use property binding to bind the property defined in the component class. So data source is equal to element data which is provided here so that is the first step to implementing a data table creating the data source and binding it to the table.

The second step is to define the column templates in the browser you can see that we have four columns the position number name weight and symbol in the code, we define the four columns each inside its ng container element physician name weight and symbol.

The ng container element will not be rendered to the Dom but it will provide an element for applying this matColumnDef directive. The matColumnDef directive is what uniquely identifies a given a column with a key physician named way and symbol inside the ng container element. We will have all the  configuration for a given column. You can see that we have the template that defines how to display the header for a given column identified using the matHeaderCellDef structural directive.

We also have another template that defines how to display the data cells of a given column using the mat cell def structural directive the to structural directives do not attach any styling to the elements the styling is taken care of by mat header cell and mat cell components next let's talk about the content of the heading and the data cells.

For the heading you can see that we just have static text number name weight and symbol but for the data cell we get access to each row of the data source we obtain a reference to each row and then access the different properties of each row, we then use interpolation to bind the data to the view so in our data source we have ten rows we iterate through the rows get a reference to each row and store it in the element variable and then we access the appropriate property in the column template.

So element.position, element.name, element.weight and element.symbol, these are the different properties for each element all right now what we have done so far is just define the column template how it's supposed to look the final step is to define the rows in the data table and for that, we make use of two more components to define the table header row we make use of the mat-header-row component and to determine which columns have to be displayed in the table matHeaderRowDef structural directive is used to this we assign displayed columns property which is an array of columns we have mentioned in the component class so display column is an array of strings with positioned name weight and symbol similarly to display the data rows we make use of the mat rope component now with matRowDef structural directive we also have a variable exported that we have named as row containing the data of that given row and we have to specify the columns property which contains the order in which the data cells should be rendered again this is displayed columns property so when you run this code we should have the data table working as expected position name weight and symbol and then the different rows corresponding to each entry or each item in the element array.

Let's take a more detailed look at data tables in angular material. Let's start with the displayed columns property. This property as the name suggests controls the columns to be displayed. In the browser as you can see it is just an array of strings. If I were to for example remove the symbol from this list.

Take a look at the browser the column is not displayed.

 

So the property controls which of the columns have to be shown but there is more to it than just showing and hiding of columns. The order in which you specify the fields to be displayed in the order in which the columns are displayed.

In the browser you can see that we have the order as position name weight and symbol and in the browser the columns are in the exact same order physician name weight and symbol. If you want the weight column to be the last column you just have to specify the weight column as the last column in displayed columns property.

So I'm going to cut this out and paste it after symbol if I now go back to the browser weight is displayed as the last column which now brings me to the HTML to highlight another point the order in which you specify these column templates with the ng container tag doesn't affect the order.

In any way whatsoever the order is controlled by the displayed columns property which is specified to the map header row and mat row components but what does matter with the container column template is the mat column definition attribute the value has to be a value from the displayed columns property if I've already changed position too.

Let's say position test same and take a look at the browser you can see that the code breaks and the data table is not displayed so make sure you specify the right column name to the template next let's talk about the mat row component you can see that we have two variables declared row and columns the columns property is set to displayed columns to indicate what data has to be displayed it's changing this and see what happens so in the class component I'm going to create another property called displayed columns data and in this list I'm going to remove weight.

Also back in the HTML I'm going to set columns to display columns data if you now take a look at the browser you can see that we have only three columns of data being displayed and four columns of the header the data for the weight column is hidden. so It is very much possible to set separate columns to be displayed for the header and the data but then again not sure if you would ever want to do that next.

Let's talk about the road what this helps us with is to get hold of the raw data to handle events on each row in that data table. for example, I can add a click event binding and call a method that provides us with the raw data.

Let's call this log data and pass in that row variable now in the component class we can quickly define log data accepts a row and let's just console.log it.

If I save the files and take a look at the browser open console and click on a row you can see the corresponding row data being logged in the console so if you have any action that has to be performed for example editing deleting or navigating to a different route based on this row data.

This is the way to go pass in the data extract the ID probably of that column and perform the necessary action.

Angular Material Datatable Filtering


Features like filtering sorting and pagination has been made simple in angular material.
Filtering can be achieved in three simple steps.

The first step is to create a data source as an instance of the MatTableDataSource class. so let's begin by importing MatTableDataSource from angular material.. next we create a data source property as an instance of this imported class.

So data source is going to be new mat table data source and then we pass in element data as the argument so that is our first step creating the data source as an instance of the mat table data source class second step is to create an input field where the user can enter the filter text let's add that code in the HTML mat form field then an input element.

We add the mat input attribute and also a placeholder that says filter every time the user enters some text we need to filter the data table for that we listen to the key of event.

So keep up and on keep up we are going to call a method called apply filter and to this method, we pass in the filter the text which is accessed using $event.target.value.

That is the second step creating a filter input . the final step is to define this apply filter method which filters the data source.

Now this kind of seems like magic but let me tell you how it works remember the MatTableDataSource class that we imported well that class has a property called filter when you want to filter out the data all you have to do is assign a string to that property when you assign the filter value the data source will reduce each row to a serialized form and will filter out the row.

If it does not contain that filtered value or to put it in simpler terms do the data rope contain the filter if yes only then display the row so if you take a look at the browser you can see that we have a filter input I type H and you can see it filters the elements.

So three basic steps for filtering creating the data source as an instance of MatTableDataSource creating the input filter and finally on care of that input element assigns the filter value to the filter property of the data source alright in the next tutorial. let's take a look at sorting in data tables.

app.component.ts


import { Component } from '@angular/core';
import {MatSnackBar} from '@angular/material'
import {MatDialog} from '@angular/material'
import {MatTableDataSource} from '@angular/material'
import { CustomSnackBarComponent } from './custom-snack-bar/custom-snack-bar.component';
import { DialogExampleComponent } from './dialog-example/dialog-example.component';

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.scss']
})
export class AppComponent {
  displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
  dataSource = new MatTableDataSource(ELEMENT_DATA);
  numbers=[];
  constructor(private snackBar: MatSnackBar, public dialog: MatDialog){
    for(let i=0; i<1000 ; i++){
      this.numbers.push(i);
    }
  }

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

  openSnackBar(message, dismiss){
    let snackBarRef=this.snackBar.open(message,dismiss, {duration:2000});
    snackBarRef.afterDismissed().subscribe(()=>{
      console.log('The snackbar was dismissed');
    });

    snackBarRef.onAction().subscribe(()=>{
      console.log('The snackbar action was triggered');
    });
  }

  openCustomSnackBar(){
    this.snackBar.openFromComponent(CustomSnackBarComponent, {duration:2000});
  }

  openDialog(){
    let dialogRef=this.dialog.open(DialogExampleComponent, {data: {name: 'Manoj'}});
    dialogRef.afterClosed().subscribe(result=>{
      console.log('Dialog result', result);
    })
  }
}

app.component.html


<button mat-button (click)="openSnackBar('Item deleted','undo')">
  Delete
</button>
<button mat-button (click)="openCustomSnackBar('Item deleted','undo')">
  Custom Snack Bar
</button>

<button mat-raised-button (click)="openDialog()">
  Open Dialog
</button>

<cdk-virtual-scroll-viewport itemSize="100" class="container">
  <div *cdkVirtualFor="let number of numbers" class="number">{{number}}</div>
</cdk-virtual-scroll-viewport>

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

<mat-table [dataSource]="dataSource" class="mat-elevation-z8">
  <!-- 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>

material.module.ts


import { NgModule } from '@angular/core';
import
{
    MatButtonModule,
    MatButtonToggleModule,
    MatSnackBarModule,
    MatDialogModule,
    MatTableModule,
    MatFormFieldModule,
    MatInputModule
}
from '@angular/material'

const MaterialComponents=
[   
    MatButtonModule,
    MatButtonToggleModule,
    MatSnackBarModule,
    MatDialogModule,
    MatTableModule,
    MatFormFieldModule,
    MatInputModule    
];

@NgModule({
 imports: [MaterialComponents],
 exports: [MaterialComponents]
})
export class MaterialModule { }

 



Summary


So to summarize there are three steps in implementing a data table in angular material first up define the data source and the columns to be displayed second step defines the column templates and
finally, the third step includes the header and the row definitions so we are able to create a very basic data table we copy-pasted the code and did not code anything as such so in the next tutorial let's also try to make some changes and see how that impacts the data table that will give you guys a much better idea of how the data table works.

Alright then I hope that now you have a much a better understanding of how a data table works in angular material next let's take a look at filtering salting and pagination in data tables thank you guys for reading.

you're free to subscribe I'll see you

guys in the next tutorial

Post a Comment

2 Comments

  1. This comment has been removed by the author.

    ReplyDelete
  2. Thanks for provide great informatic and looking beautiful blog, really nice required information & the things i never imagined and i would request, wright more blog and blog post like that for us. Thanks you once again.
    best web design company in coimbatore

    ReplyDelete

Thanks for your valuable time.