Angular Material Datatable With Angular 6 - Part One

In this part of series, we are going to learn that How to use Angular Material Datatable with Angular6, we will learn to implement Pagination, Sorting, Searching the records using Material Datatable.

Introduction
 
In this part of the article, we will learn about how to integrate Angular Material Datatable into an Angular 6 app with server-side Pagination, Filtering, and Sorting data. We will cover all the scenarios from the beginning so that beginners can implement and use Angular Material Datatable component in their applications.
 
What is Datatable?
 
A data table is a very flexible tool by which we can perform so many operations in an easy manner. Within the data table you can get so many options to manage the data with their features like pagination, sorting, and filtering.
 
In this article, I'm going to use Angular Material Datatable, which is the part of Material Design that performs various kinds of operations with the server-side data.
 
So let's implement DataTable with our Angular 6 application.
 
Installation
 
To use the Angular Material Data table component, we should install angular material dependencies by using the following npm command.
  1. npm install --save @angular/material @angular/cdk @angular/animations   
So, now we are ready to use Angular Material components in our application.
 
After that we should import all the dependencies into the module.ts file as described below. 
  1. import { BrowserModule } from '@angular/platform-browser';  
  2. import { NgModule } from '@angular/core';  
  3.   
  4. // To use material components  
  5. import { MatToolbarModule , MatMenuModule , MatInputModule , MatTableModule ,MatButtonModule,MatCardModule,MatTableDataSource,MatPaginatorModule,MatSortModule} from '@angular/material';  
  6. import { BrowserAnimationsModule } from '@angular/platform-browser/animations';  
  7.   
  8. // To use routing  
  9. import { routing } from './routes';  
  10. // To implement services  
  11. import { HttpModule }    from '@angular/http';  
  12. import { DataServiceService } from './service/data-service.service';  
  13. import { AppComponent } from './app.component';  
  14.   
  15.   
  16. @NgModule({  
  17.   declarations: [  
  18.     AppComponent,  
  19.   ],  
  20.   imports: [  
  21.     HttpModule,  
  22.     routing,  
  23.     BrowserAnimationsModule,  
  24.     BrowserModule,  
  25.     MatToolbarModule , MatMenuModule , MatInputModule , MatTableModule ,MatButtonModule,MatCardModule,MatPaginatorModule,MatSortModule  
  26.   ],  
  27.   exports:[  
  28.     MatToolbarModule , MatMenuModule , MatInputModule , MatTableModule ,MatButtonModule,MatCardModule,MatPaginatorModule,MatSortModule  
  29.   ],  
  30.   providers: [DataServiceService],  
  31.   bootstrap: [AppComponent]  
  32. })  
  33. export class AppModule { }  
I have imported the different material components because we are going to use multiple Angular Material components in this article.
 
Now let's quickly set up the routing for our app. For that create the routes.ts file inside the app folder and paste the following code snippet.
  1. import { ModuleWithProviders } from '@angular/core';  
  2. import { Routes, RouterModule } from '@angular/router';  
  3. import { AppComponent } from './app.component';  
  4. import { CombinedComponent } from './combined/combined.component';  
  5. import { WithfilteringComponent } from './withfiltering/withfiltering.component';  
  6. import { WithpaginationComponent } from './withpagination/withpagination.component';  
  7. import { WithsortingComponent } from './withsorting/withsorting.component';  
  8. import { DefaultComponent } from './default/default.component';  
  9.   
  10. const appRoutes: Routes = [  
  11.     { path: '', redirectTo: 'Default', pathMatch: 'full' },  
  12.     { path: 'Default', component: DefaultComponent },  
  13.     { path: 'WithPagination', component: WithpaginationComponent },  
  14.     { path: 'WithFiltering', component: WithfilteringComponent },  
  15.     { path: 'WithSorting', component: WithsortingComponent },  
  16.     { path: 'Combined', component: CombinedComponent }  
  17.   
  18. ];  
  19.   
  20. export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);  
We have implemented the basic routing configuration, our next step is to configure the homepage for this article from where we can go to the different pages using routing.
 
Before that, let's configure our home page using the app.component.html file. Open the file and replace the following source code.
  1. <mat-toolbar color="accent">  
  2.     <span>Manav Pandya - C#Corner</span>  
  3.     <span class="demo-toolbar"></span>  
  4.     <button mat-button href="www.asp-dotnet-mvc-tutorials.blogspot.in">Go To My Blog</button>  
  5.     <button mat-button [matMenuTriggerFor]="menu">Select Table From Below Menu</button>  
  6.     <mat-menu #menu="matMenu">  
  7.         <button [routerLink]="['/Default']" mat-menu-item>Default DataTable</button>  
  8.         <button [routerLink]="['/WithPagination']" mat-menu-item>Table With Pagination</button>  
  9.         <button [routerLink]="['/WithFiltering']" mat-menu-item>Table With Filtering</button>  
  10.         <button [routerLink]="['/WithSorting']" mat-menu-item>Table With Sorting</button>  
  11.         <button [routerLink]="['/Combined']" mat-menu-item>Combined DataTable</button>  
  12.     </mat-menu>  
  13. </mat-toolbar>  
  14.   
  15. <router-outlet>  
  16. </router-outlet>  
Here we have used <router-outlet> to load our routing parameters as defined in routes.ts .
 
Simple Datatable
 
Before implementing complex Datatable with different functionalities, we will implement a simple Datatable so that we get to know the difference between them.
 
For that, create a new component named default, where we will implement a simple material data table.
  1. ng g c default  
Open the default.component.html file and replace the following lines of source code.
  1. <mat-card>  
  2.     <div class="alert alert-info">  
  3.         <strong>Simple Angular Material DataTable</strong>  
  4.     </div>  
  5.     <div class="example-container mat-elevation-z8">  
  6.         <mat-table #Table [dataSource]="MyDataSource">  
  7.   
  8.             <!-- For ID -->  
  9.             <ng-container matColumnDef="id">  
  10.                 <mat-header-cell *matHeaderCellDef> ID </mat-header-cell>  
  11.                 <mat-cell *matCellDef="let post"> {{post.id}} </mat-cell>  
  12.             </ng-container>  
  13.   
  14.             <!-- For User ID -->  
  15.             <ng-container matColumnDef="userId">  
  16.                 <mat-header-cell *matHeaderCellDef> User ID </mat-header-cell>  
  17.                 <mat-cell *matCellDef="let post"> {{post.userId}} </mat-cell>  
  18.             </ng-container>  
  19.   
  20.             <!-- For Title -->  
  21.             <ng-container matColumnDef="title">  
  22.                 <mat-header-cell *matHeaderCellDef> Title </mat-header-cell>  
  23.                 <mat-cell *matCellDef="let post"> {{post.title}} </mat-cell>  
  24.             </ng-container>  
  25.   
  26.             <!-- For Body -->  
  27.             <ng-container matColumnDef="body">  
  28.                 <mat-header-cell *matHeaderCellDef> Body Text </mat-header-cell>  
  29.                 <mat-cell *matCellDef="let post"> {{post.body}} </mat-cell>  
  30.             </ng-container>  
  31.   
  32.             <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>  
  33.             <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>  
  34.         </mat-table>  
  35.     </div>  
  36. </mat-card>  
Code Explanation
 
Here in this example, I have used different markup tags of material components, let's see the description about that. 
  • <mat-table>
    It defines the material design data table, which is used to render the number of records using the data table. 

  • <ng-container>
    ng-container is a directive, which acts as a structural directive. 
     
  • <mat-header-cell>
    It defines the header text of a mat-table directive.

  • <mat-cell>
    Used to print the value of a specific cell of a material table.

  • <mat-header-row>
    It takes the array of values to act as data row template, that renders out table wise.

  • <mat-row>
    It is used to show the content of the row for the data table.

  • DataSource="MyDataSource"
    Datasource is the primary property, which is used to populate the data table with the data and the other operations like Pagination, Sorting, Searching and Filtering will completely depend on the data populated using DataSource property.
So far, we have implemented the simple data table page with the HTML required to create the data table.
 
Now, open the default.component.ts file and replace the give lines of source code. 
  1. import { Component, OnInit } from '@angular/core';  
  2. import { MatTableDataSource } from '@angular/material';  
  3. import { DataServiceService } from '../service/data-service.service';  
  4. import { MatSort } from '@angular/material';  
  5. import { BehaviorSubject } from 'rxjs/BehaviorSubject';  
  6. import { Observable } from 'rxjs/Observable';  
  7.   
  8. @Component({  
  9.   selector: 'app-default',  
  10.   templateUrl: './default.component.html',  
  11.   styleUrls: ['./default.component.css']  
  12. })  
  13. export class DefaultComponent implements OnInit {  
  14.   
  15.   MyDataSource: any;  
  16.   displayedColumns = ['id''userId','title','body'];  
  17.   
  18.   constructor(public dataService: DataServiceService) { }  
  19.   
  20.   ngOnInit() {  
  21.     this.RenderDataTable();  
  22.   }  
  23.   
  24.   RenderDataTable() {  
  25.     this.dataService.GetAllRecords()  
  26.       .subscribe(  
  27.       res => {  
  28.         this.MyDataSource = new MatTableDataSource();  
  29.         this.MyDataSource.data = res;  
  30.         console.log(this.MyDataSource.data);  
  31.       },  
  32.       error => {  
  33.         console.log('There was an error while retrieving Posts !!!' + error);  
  34.       });  
  35.   }  
  36.   
  37. }  
As you can see that there is one method named RenderDataTable(), which is used to get the data from the service and populate the data table using DataSource property.
 
To get data, I'm using the free online REST service [Fake API data] and to know more about that, than just go through the following link. 
To populate our datatable we are using the service file named data-service.service.ts, create the service using given command.
  1. ng g s /service/data-service  
Open data-service.service.ts file and replace with the following source code.
  1. import { Injectable } from '@angular/core';  
  2. import { Http, Response, Headers, RequestOptions } from '@angular/http';  
  3. import { Observable } from 'rxjs/Observable';  
  4. import { Observer } from 'rxjs/Observer';  
  5. import 'rxjs/add/operator/map';  
  6. import 'rxjs/add/operator/catch';  
  7. import 'rxjs/add/operator/toPromise';  
  8. import 'rxjs/add/observable/throw';  
  9.   
  10. @Injectable()  
  11. export class DataServiceService {  
  12.   
  13.   private headers = new Headers({ 'Content-Type''application/json' });  
  14.   _baseUrl: string = '';  
  15.   
  16.   // For Using Fake API by Using It's URL  
  17.   constructor(private http: Http) {  
  18.     this._baseUrl = "https://jsonplaceholder.typicode.com/";  
  19.   }  
  20.   
  21.   // To fill the Datatable for Default Table [Dummy Data]  
  22.   public GetAllRecords() {  
  23.     return this.http.get(this._baseUrl + 'posts')  
  24.       .map((res: Response) => {  
  25.         return res.json();  
  26.       })  
  27.       .catch(this.handleError);  
  28.   }  
  29.   
  30.   // To provide error description   
  31.   private handleError(error: Response | any) {  
  32.     console.error(error.message || error);  
  33.     return Observable.throw(error.status);  
  34.   }  
  35. }  
For getting sample data im using https://jsonplaceholder.typicode.com/posts, which provides me the 100 records as a fake/dummy data.
 
This is how we have implemented a simple Material data table, now let's see the output. 
 
Angular Material Datatable
 
As you can see above our data populated inside the data table, but it's just a simple table with the list of 100 records, but the problem is that there are 100 records listed in the page. Instead we can use pagination to limit data to the specific number of results per page.
 
Data table With Pagination
 
Paging reduces our result to the chunks of results for the instance, and you can navigate forward or backward  using pagination.
 
For that, I'm going to create a component named with pagination by using the following command.
  1. ng g c withpagination  
Now open with pagination.component.html and paste snippet :
  1. <mat-card>  
  2.     <div class="alert alert-info">  
  3.         <strong>Angular Material DataTable With Pagination</strong>  
  4.     </div>  
  5.     <div class="example-container mat-elevation-z8">  
  6.         <mat-table #Table [dataSource]="MyDataSource">  
  7.   
  8.             <!-- For ID -->  
  9.             <ng-container matColumnDef="id">  
  10.                 <mat-header-cell *matHeaderCellDef> ID </mat-header-cell>  
  11.                 <mat-cell *matCellDef="let post"> {{post.id}} </mat-cell>  
  12.             </ng-container>  
  13.   
  14.             <!-- For Album ID -->  
  15.             <ng-container matColumnDef="albumId">  
  16.                 <mat-header-cell *matHeaderCellDef> Album ID </mat-header-cell>  
  17.                 <mat-cell *matCellDef="let post"> {{post.albumId}} </mat-cell>  
  18.             </ng-container>  
  19.   
  20.             <!-- For Title -->  
  21.             <ng-container matColumnDef="title">  
  22.                 <mat-header-cell *matHeaderCellDef> Title </mat-header-cell>  
  23.                 <mat-cell *matCellDef="let post"> {{post.title}} </mat-cell>  
  24.             </ng-container>  
  25.   
  26.             <!-- For Image -->  
  27.             <ng-container matColumnDef="url">  
  28.                 <mat-header-cell *matHeaderCellDef> Image </mat-header-cell>  
  29.                 <mat-cell style="text-align: center;" *matCellDef="let post">  
  30.                     <img class="img-rounded" src={{post.url}}/>  
  31.                 </mat-cell>  
  32.             </ng-container>  
  33.   
  34.             <!-- For Thumbnail Photo -->  
  35.             <ng-container matColumnDef="thumbnailUrl">  
  36.                 <mat-header-cell *matHeaderCellDef> Thumbnail </mat-header-cell>  
  37.                 <mat-cell style="text-align: center;" *matCellDef="let post">  
  38.                     <img class="img-rounded" src={{post.thumbnailUrl}}/>  
  39.                 </mat-cell>  
  40.             </ng-container>  
  41.   
  42.             <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>  
  43.             <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>  
  44.         </mat-table>  
  45.   
  46.         <!-- To use pagination in DataTable  -->  
  47.   
  48.         <mat-paginator #paginator [pageSize]="10" [pageSizeOptions]="[5, 10, 20]">  
  49.         </mat-paginator>  
  50.     </div>  
  51. </mat-card>  
From the above code you can see that I have included a <mat-paginator> directive to use the pagination feature.
 
<mat-paginator> options are as follow,
  • #paginator - trigger from component to define pagination within datatable
  • [pageSize] - define how many rows will be displayed per page by default 
  • [pageSizeOptions] - define how many rows you want to see at a time, you can change as per your requirement
Open the withpagination.component.ts file and paste the following code snippet.
  1. import { Component, OnInit ,ViewChild} from '@angular/core';  
  2. import { MatTableDataSource , MatPaginator } from '@angular/material';  
  3. import { DataServiceService } from '../service/data-service.service';  
  4. import { MatSort } from '@angular/material';  
  5. import { BehaviorSubject } from 'rxjs/BehaviorSubject';  
  6. import { Observable } from 'rxjs/Observable';  
  7.   
  8. @Component({  
  9.   selector: 'app-withpagination',  
  10.   templateUrl: './withpagination.component.html',  
  11.   styleUrls: ['./withpagination.component.css']  
  12. })  
  13. export class WithpaginationComponent implements OnInit {  
  14.   
  15.   MyDataSource: any;  
  16.   displayedColumns = ['id''albumId','title','url','thumbnailUrl'];  
  17.   
  18.   constructor(public dataService: DataServiceService) { }  
  19.   @ViewChild(MatPaginator) paginator: MatPaginator;  
  20.   
  21.   ngOnInit() {  
  22.     this.RenderDataTable();  
  23.   }  
  24.   
  25.   RenderDataTable() {  
  26.     this.dataService.GetAllPhotos()  
  27.       .subscribe(  
  28.       res => {  
  29.         this.MyDataSource = new MatTableDataSource();  
  30.         this.MyDataSource.data = res;  
  31.         this.MyDataSource.paginator = this.paginator;  
  32.         console.log(this.MyDataSource.data);  
  33.       },  
  34.       error => {  
  35.         console.log('There was an error while retrieving Photos !!!' + error);  
  36.       });  
  37.   }  
  38. }  
Code explanation
 
For pagination, I have used @ViewChild(MatPaginator), that indicates we have used the functionality of a material design MatPaginator by creating an object paginator.
 
And that I have referenced object to MyDataSource property like this:
  1. this.MyDataSource.paginator= this.paginator // which is the view child paginator object    
For populating this datatable, I've used the URL https://jsonplaceholder.typicode.com/albums/1/photos
 
Open the data-service.service.ts file and add the following method to get all the photos from the API.
  1. // To fill the Datatable with Photos [Dummy Data]  
  2.  public GetAllPhotos() {  
  3.    return this.http.get(this._baseUrl + 'albums/1/photos')  
  4.      .map((res: Response) => {  
  5.        return res.json();  
  6.      })  
  7.      .catch(this.handleError);  
  8.  }  
When you execute the app, the output will be something like this.
 
Angular Material Datatable
 
Datatable with Sorting 
 
Sorting is the important part, which is mainly used to simplify the data in either ascending or descending order 
 
To use Sorting in the Angular app using Material Datatable, we should include the paginator into the module file like this.
  1. import { MatSort } from '@angular/material';  
Now let's create the new component by using ng command.
  1. ng g c withsorting  
Open withsorting.component.html file and paste,
  1. <mat-card>  
  2.     <div class="alert alert-info">  
  3.         <strong>Angular Material DataTable With Sorting</strong>  
  4.     </div>  
  5.     <div class="example-container mat-elevation-z8">  
  6.         <mat-table #Table [dataSource]="MyDataSource" matSort>  
  7.   
  8.             <!-- For ID -->  
  9.             <ng-container matColumnDef="id">  
  10.                 <mat-header-cell *matHeaderCellDef mat-sort-header> ID </mat-header-cell>  
  11.                 <mat-cell *matCellDef="let post"> {{post.id}} </mat-cell>  
  12.             </ng-container>  
  13.   
  14.             <!-- For Post ID -->  
  15.             <ng-container matColumnDef="userId">  
  16.                 <mat-header-cell *matHeaderCellDef mat-sort-header> User ID </mat-header-cell>  
  17.                 <mat-cell *matCellDef="let post"> {{post.userId}} </mat-cell>  
  18.             </ng-container>  
  19.   
  20.             <!-- For Name -->  
  21.             <ng-container matColumnDef="title">  
  22.                 <mat-header-cell *matHeaderCellDef mat-sort-header> Title </mat-header-cell>  
  23.                 <mat-cell *matCellDef="let post"> {{post.title}} </mat-cell>  
  24.             </ng-container>  
  25.   
  26.             <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>  
  27.             <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>  
  28.         </mat-table>  
  29.   
  30.         <!-- To paginate between pages with search -->  
  31.         <mat-paginator #paginator [pageSize]="10" [pageSizeOptions]="[5, 10, 20]">  
  32.         </mat-paginator>  
  33.     </div>  
  34. </mat-card>  
As you've noticed, there are two terms regarding the sorting,
  • matSort - it defines that the datatable is sortable 
  • mat-sort-header - this term is used to indicate that every column is identically listening for sorting changes 
Open withsorting.component.ts file and paste the following lines of source code.
  1. import { Component, OnInit ,ViewChild} from '@angular/core';  
  2. import { MatTableDataSource,MatPaginator,MatSort } from '@angular/material';  
  3. import { DataServiceService } from '../service/data-service.service';  
  4. import { BehaviorSubject } from 'rxjs/BehaviorSubject';  
  5. import { Observable } from 'rxjs/Observable';  
  6.   
  7. @Component({  
  8.   selector: 'app-withsorting',  
  9.   templateUrl: './withsorting.component.html',  
  10.   styleUrls: ['./withsorting.component.css']  
  11. })  
  12. export class WithsortingComponent implements OnInit {  
  13.   
  14.   MyDataSource: any;  
  15.   displayedColumns = ['id''userId','title'];  
  16.   @ViewChild(MatPaginator) paginator: MatPaginator;  
  17.   @ViewChild(MatSort) sort: MatSort;  
  18.   
  19.   constructor(public dataService: DataServiceService) { }  
  20.   
  21.   ngOnInit() {  
  22.     this.RenderDataTable();  
  23.   }  
  24.   
  25.   RenderDataTable() {  
  26.     this.dataService.GetAllAlbums()  
  27.       .subscribe(  
  28.       res => {  
  29.         this.MyDataSource = new MatTableDataSource();  
  30.         this.MyDataSource.data = res;  
  31.         this.MyDataSource.sort = this.sort;  
  32.         this.MyDataSource.paginator = this.paginator;  
  33.         console.log(this.MyDataSource.data);  
  34.       },  
  35.       error => {  
  36.         console.log('There was an error while retrieving Albums !!!' + error);  
  37.       });  
  38.   }  
  39.   
  40. }  
Code explanation
 
For sorting, I have used @ViewChild(MatSort), that indicates we have used the functionality of a material design MatSort by creating object sort.
 
And for that, I have the referenced object to MyDataSource property like this.
  1. this.MyDataSource.sort = this.sort // which is viewchild sorting object  
For populating the data, I'm going to use the API URL  https://jsonplaceholder.typicode.com/albums
 
Now open the data-service.service.ts and add the following method.
  1. // To fill the Datatable with Albums [Dummy Data]  
  2.   public GetAllAlbums() {  
  3.     return this.http.get(this._baseUrl + 'albums')  
  4.       .map((res: Response) => {  
  5.         return res.json();  
  6.       })  
  7.       .catch(this.handleError);  
  8.   }  
We have implemented sorting functionality with Datatable, execute the app and you can see the output like this.
 
Angular Material Datatable
 
As you can see my data are populated and the data table is sorted with the descending order.
 
Conclusion 
 
In this part of the article, we have integrated three types of different operations using Angular Material Datatable which are listed below.
  • Simple Datatable Integration
  • Data table with Pagination
  • Data table with Sorting 
Further, we will expand our datatable by adding more features like searching, and the combined example of Angular material datatable with all possible features. Until then stay tuned and keep learning.