How to build Reusable Table Component in Angular
Angular projects are fun to work on…
However certain important take a way’s while working on the same technology:
- Library to keep handy is the Angular Material Library (material.angular.io). Material Library’s table content is one such stop which will not only make our lives easy to build a reusable or dynamic table, but also seamlessly amalgamate basic functionalities such as Pagination, Sorting and Search Operations 🙈.
- Developing a Dynamic Mat-Table component and re-using it wherever required helps us to be in line with the principle of “DRY” (Don’t Repeat Your Code).
- Without any further delay’s let proceed to build a Dynamic table component that can be used across the project.
In this article we will learn how to create dynamic/reusable table in angular using angular material library.
First of create an angular project using ng new <PROJECT_NAME>
command. The latest stable version of angular is V11.2.9.
Once we create our angular project we need to install Angular Material. We can install using ng add @angular/material
command.
Now we will add material theme in styles.scss
file.
@import '@angular/material/prebuilt-themes/deeppurple-amber.css';
Now lets create a reusable table component using ng g c components/table
command. This will create a new folder inside app named as component and a table component inside components.
FYI: Here g
is a short for generate
and c
is a short forcomponent
.
Now we need to import MatTableModule
in app.component.ts file then add this in imports array of @NgModule
.
Now in table.component.ts file create 2 Input properties.
@Input() tableColumns: Array<Column> = [];
@Input() tableData: Array<T> = [];
add two properties like below.
displayedColumns: Array<string> = [];
dataSource: MatTableDataSource<T> = new MatTableDataSource();
Then in your ngOnInit method add this.
this.displayedColumns = this.tableColumns.map((c) => c.columnDef);
this.dataSource = new MatTableDataSource(this.tableData);
You table.component.ts should look like below.
Now we will create a column.ts file in table component which will look like below.
export interface Column {
columnDef: string;
header: string;
cell: Function;
isLink?: boolean;
url?: string;
}
Lets understand each one by one.
tableColumns will be and array of Columns which will have 3 mandatory properties (columnDef, header, cell) and 2 option properties which are (isLink, url).
columnDef is the key from dataSource.
header is the value which will be show as Column header.
cell will define a function to get value from datasource.
tableData will be your data which we will be getting from API or it can be hardcoded json also.
displayedColumns will be array of column name.
The reason to use MatTableDataSource is, it’s easier to integrate sorting, pagination and searching to the table.
Now paste below code in your table.component.html
Now our table component is ready. now we will use this component in our app component.
First create 2 new files in app folder, elements.ts and employee.ts and add given code in respective files.
export interface Element {
position: number,
name: string,
weight: number,
symbol: string
}export interface Employee {
name: string,
role: string,
skills: string
}
now go to app.component.ts and import both interfaces.
Once you import interfaces add below code in app.component.ts
tableColumns: Array<Column> = [{ columnDef: 'position', header: 'Position', cell: (element: Record<string, any>) => `${element['position']}` },{ columnDef: 'name', header: 'Name', cell: (element: Record<string, any>) => `${element['name']}`, isLink: true, url: 'abc'},{ columnDef: 'weight', header: 'Weight', cell: (element: Record<string, any>) => `${element['weight']}` },{ columnDef: 'symbol', header: 'Symbol', cell: (element: Record<string, any>) => `${element['symbol']}` },
];tableData: Array<Element> = [
{ 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' },
];
Now add below code in you app.component.html
<h1>Dynamic Table Component</h1><h2>Table one</h2><app-table
[tableColumns]="tableColumns"
[tableData]="tableData">
</app-table>
Now run your local server and you will see table like below on your app component.
Now let create one more variant of this table.
Add below code in app.component.ts
anotherTableColumns: Array<Column> = [{ columnDef: 'name', header: 'Name', cell: (element: Record<string, any>) => `${element['name']}` },{ columnDef: 'role', header: 'Role', cell: (element: Record<string, any>) => `${element['role']}` },{ columnDef: 'skills', header: 'Skills', cell: (element: Record<string, any>) => `${element['skills']}` },];anotherTableData: Array<Employee> = [
{ name: 'John', role: 'Fullstack Developer', skills: 'Angular, Typescript, React' },
{ name: 'Mile', role: 'Java Developer', skills: 'Java' },
{ name: 'Peter', role: 'DevOps', skills: 'AWS, GCP' }
]
Now call table component in app.component.html and pass this data and Input binding.
<h2>Table Two</h2><app-table
[tableColumns]="anotherTableColumns"
[tableData]="anotherTableData">
</app-table>
Now if you will refresh your page then will see second table on your page which will look like below.
So, we used our reusable table component on 2 places without writing any extra code, we just have to pass data related to columns and datasource, rest out table component will take care of.
Let’s understand most important part of this.
{ columnDef: 'name', header: 'Name', cell: (element: Record<string, any>) => `${element['name']}`, isLink: true, url: 'abc'},
columnDef: it is the name of the property from dataSource.
header: value which we have to show as column header
cell: cell is a function which will be executed for each object in dataSource or you can say it will be called on each row of table.
Now we have 2 extra property for this columns which are isLink
and url
.
In my earlier project we got a requirement from client that we have to render users details on table and on click on user name it should redirect to new page and should show that user’s details.
So, in this scenario we added anchor link in user name column, so that when any person will click on that it will open new page and will display respective user’s details.
What more you can do in this reusable / dynamic table.
- We can manage sorting for each column by passing extra property
isSortable: true
intableColumn
and also add this inColumn
interface likeisSortable?: boolean
. Then in your table.component.html file you can if that column has this value true you can sorting on that column. - Same as like step 1 if we want to add filter for table we can pass another property
isFilterable: true
intableColumn
and also add this property inColumn
interface likeisFilterbale?: boolean
.
The reason to use MatTableDataSource is, it’s easier to integrate sorting, pagination and searching to the table. Else we need to perform these operations manually by defining the respective functions to modify the data and update the view accordingly.
You can find code on my github profile — https://github.com/piyush303/Angular-Dynamic-Table
You can also play with code on stackblitz —
https://stackblitz.com/edit/angular-reusable-table
Thank you for giving your time, I hope you have learnt something new today.
if you like this article please give a clap.
References: