Angular Material Table With API Call

Table of Contents
Overview
In this example, we will create a data table with Angular Materials and retrieve the data via API call. The table will have sort and pagination. The http service will call the users option from the free API https://random-data-api.com
Code for this article
Get Source CodeIf you do not have Angular Material installed please run the following CLI command from your application root folder.
ng add @angular/material
How to Create a module for Material Library imports
Here is a link on how to set up a separate module for material libraries.
Create an Interface
ng generate interface models/random-users
Add the following code to the Interface. To keep this example simple, parts of the data structure is not defined.
export interface IRandomUsers {
id: number,
uid: number,
password: string,
first_name: string,
last_name: string,
username: string,
email: string,
avatar: string,
gender: string,
phone_number: string,
social_insurance_number: string,
date_of_birth: Date,
address: {
city: string,
street_name: string,
street_address: string,
zip_code: string,
state: string,
country: string,
coordinates: {
lat: number,
lng: number
}
}
}
Create a Service
Create a new service labeled random-api under a folder labeled services. This service will use https://random-data-api.com users.
ng g s services/random-api
In the random-users.service.ts file add the following code.
import { Observable } from 'rxjs';
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
import { IRandomUsers } from 'src/app/models/random-users';
@Injectable({
providedIn: 'root'
})
export class RandomApiService {
private baseURL = 'https://random-data-api.com';
constructor(private http: HttpClient) { }
getRandomUsers(): Observable<IRandomUsers> {
const URL = `${this.baseURL}/api/users/random_user?size=10`;
return this.http.get<IRandomUsers>(URL);
}
}
Building the Component
Create a new component for the data table.
ng g c components/random-users-table --module=app
Typescript
TypeScript code below in the random-users-table.component.ts file.
import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
import { MatSort} from '@angular/material/sort';
import { MatPaginator } from '@angular/material/paginator';
import { MatTableDataSource } from '@angular/material/table';
import { MatSnackBar, MatSnackBarConfig } from '@angular/material/snack-bar';
import { HttpErrorResponse } from '@angular/common/http';
import { RandomApiService } from 'src/app/services/random-api.service';
import { IRandomUsers } from 'src/app/models/random-users';
@Component({
selector: 'app-random-users-table',
templateUrl: './random-users-table.component.html',
styleUrls: ['./random-users-table.component.scss']
})
export class RandomUsersTableComponent implements OnInit, OnDestroy {
private subs = new Subscription();
displayedColumns: string[] = ['action', 'avatar', 'username', 'email', 'date_of_birth', 'latidtude', 'longitude',];
public dataSource: MatTableDataSource<IRandomUsers>;
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
@ViewChild(MatSort, { static: true }) sort: MatSort;
private dataArray: any;
constructor(private financeService: RandomApiService, private _snackBar: MatSnackBar) { }
ngOnInit() {
this.subs.add(this.financeService.getRandomUsers()
.subscribe((res) => {
console.log(res);
this.dataArray = res;
this.dataSource = new MatTableDataSource<IRandomUsers>(this.dataArray);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
},
(err: HttpErrorResponse) => {
console.log(err);
}));
}
ngOnDestroy() {
if (this.subs) {
this.subs.unsubscribe();
}
}
public openRecord(id: number, name: string): void {
this._snackBar.open(`Record ${id} ${name} `, 'Close', {
horizontalPosition: 'center',
verticalPosition: 'top',
});
}
}
Break Down of the TypeScript code
The displayColumns is a string array with column names. The columns will be displayed in the order they are defined. In this case, action is the first column on the left and the longitude is the last column to the right.
public displayedColumns: string[] = ['action', 'avatar', 'username', 'email', 'date_of_birth', 'latidtude', 'longitude'];
displayColumns is passed to the Material Table HTML table row tags and each column has to have a corresponding matColumnDef tag.
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
The @ViewChild() decorators are used as references for Pagination and Sorting. The Material Table will handle the logic you just need to pass it to MatTableDataSource
@ViewChild(MatPaginator, {static: true}) paginator: MatPaginator;
@ViewChild(MatSort, {static: true}) sort: MatSort;
Passing the API Data, Sort, and Pagination instances to MatTableDataSource.
this.dataArray = res.majorIndexesList;
this.dataSource = new MatTableDataSource<RecordsModel>(this.dataArray);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
Added a Material SnackBar to show the ID and Username when clicking on the view button under the action column.
constructor(private financeService: RandomApiService, private _snackBar: MatSnackBar) { }
...
public openRecord(id: number, name: string): void {
this._snackBar.open(`Record ${id} ${name} `, 'Close', {
horizontalPosition: 'center',
verticalPosition: 'top',
});
}
HTML
HTML Markup Code for the random-users-table.component.html file.
<div class="mat-elevation-z1">
<table mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="action">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Action</th>
<td mat-cell *matCellDef="let element" class="left-text">
<button mat-stroked-button color="primary" (click)="openRecord(element.id, element.username)">View</button>
</td>
</ng-container>
<ng-container matColumnDef="avatar">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Avatar </th>
<td mat-cell *matCellDef="let element" class="left-text">
<img src={{element.avatar}} width="50" height="auto" />
</td>
</ng-container>
<ng-container matColumnDef="username">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Username </th>
<td mat-cell *matCellDef="let element" class="left-text"> {{element.username}} </td>
</ng-container>
<ng-container matColumnDef="email">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Email </th>
<td mat-cell *matCellDef="let element" class="left-text"> {{element.email | number:'2.1-2'}} </td>
</ng-container>
<ng-container matColumnDef="date_of_birth">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Date of Birth </th>
<td mat-cell *matCellDef="let element" class="left-text">{{element.date_of_birth | date: 'EEEE MMM dd, yyy'}} </td>
</ng-container>
<ng-container matColumnDef="latidtude">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Latitude </th>
<td mat-cell *matCellDef="let element" class="left-text"> {{element.address.coordinates.lat | number:'2.1-2'}} </td>
</ng-container>
<ng-container matColumnDef="longitude">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Longitude </th>
<td mat-cell *matCellDef="let element" class="left-text"> {{element.address.coordinates.lng | number:'2.1-2'}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSizeOptions]="[5]"></mat-paginator>
</div>
Break Down of the HTML code
This option enables how much height for the table. mat-elevation-z1 is the lowest and you can go up to mat-elevation-z8 which will have a pronounced 3D shadow effect.
<div class="mat-elevation-z1">
Adding mat-sort to the table tag will allow the use of mat-sort-header for generating sortable columns.
<table mat-table [dataSource]="dataSource" matSort>
Inside the <th header tags use mat-sort-header to enable sort on the columns you want to have the sorting feature enabled.
Each column defined in the displayColumns String array has to match one for one with matColumnDef.
<ng-container matColumnDef="avatar">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Avatar </th>
<td mat-cell *matCellDef="let element" class="left-text">
<img src={{element.avatar}} width="50" height="auto" />
</td>
</ng-container>
Mat-Paginator defines the available page sizes.
<mat-paginator [pageSizeOptions]="[5]"></mat-paginator>
So you could add more page sizes with 10 being the default. Click here to read more about material pagination.
<mat-paginator [pageSizeOptions]="[5, 10, 20]" [pageSize]="10"></mat-paginator>
CSS or SCSS file
CSS for the random-users-table.component.scss
table {
width: 100%;
}
mat-header-cell, mat-cell {
justify-content: left;
}
.left-text {
text-align: left;
}
Update Root Component to Render the Table
Finally update the root component app.module.html with the following:
<app-random-users-table></app-random-users-table>
You must be logged in to post a comment.