Angular Material Table provides a feature to stick or freeze columns, rows, footer and header. In this guide, you will learn how to add sticky properties on dynamically created columns.
It becomes difficult to show all columns and rows on a single screen when it contains large data sets. In such cases, we can limit the scrolling pains to much extent by freezing some of the important rows or column values.
So that even if the user scrolls around the important information doesn’t hide and is viewable all the time. This adds value to the user experience and makes data more consumable.
Let’s check implementable steps:
How to Add Sticky on Dynamic Column/ Rows in Material Table?
Follow these steps to freeze various sections of dynamically generated data table using Angular Material:
Step 1) Create Angular App
Step 2) Add Material Library and Update AppModule
Step 3) Create a Simple Material Table
Step 4) Freeze/ Stick Various Table Sections
Step 5) Update Class/ Create Generate Dynamic Data
Step 6) Update CSS Style for Sticky
Step 1) Create Angular App
To enable the ng command in the terminal window, make sure to instal the angular cli tool. If you already have, you can update it as well.
# Install NG CLI
npm install -g @angular/cli
#Update NG CLI
ng update
Afterwards, you can hit the following command to create a new angular project with the name provided:
ng new angular-material-table-app
Move inside the application folder
cd angular-material-table-app
Step 2) Add Material Library and Update AppModule
Thereafter creating and moving the terminal to the application folder, we will install the Material library by executing the ng add
command. This makes the installation of the material library very easy, you can choose options while installation as shown below:
ng add @angular/material
# ? Choose a prebuilt theme name, or "custom" for a custom theme: Indigo/Pink
# ? Set up global Angular Material typography styles? No
# ? Set up browser animations for Angular Material? Yes
This will update the "styles"
property array inside the angular.json file, which you can change anytime.
Import Material Module
The Material Library provides a huge set of usable API’s for its various modules and components. So we need to import only those modules, that we’re going to use in our application. This keeps our app more optimized and size-efficient.
Let’s import the MatTableModule
for creating Datatable.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
// Material Modules
import { MatTableModule } from '@angular/material/table';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, BrowserAnimationsModule, MatTableModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
Step 3) Create a Simple Material Table
Now head towards the HTML template to add the dynamically create table using the Mat Table components. We will be using the Material table components like mat-table, mat-row, mat-cell etc instead of Native HTML tags like table, tr, td. But you can easily replace them and use vice-versa
Open the app.component.html file and update it with the following code:
<div class="table-container" tabindex="0">
<mat-table [dataSource]="dataSource">
<ng-container matColumnDef="{{col}}" *ngFor="let col of displayedColumns;let i = index" [sticky]="i<3"
[stickyEnd]="i > displayedColumns.length-3">
<mat-header-cell *matHeaderCellDef> {{col}} </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element[col]}} </mat-cell>
<mat-footer-cell *matFooterCellDef> <b>Footer</b> </mat-footer-cell>
</ng-container>
<mat-row mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></mat-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
<mat-row mat-footer-row *matFooterRowDef="displayedColumns; sticky: true"></mat-row>
</mat-table>
</div>
Step 4) Freeze/ Stick Various Table Sections
<mat-table> component created the material data-table by taking the dataSource
of rows object assigned to the [dataSource]
property.
Inside the matColumnDef
we used the ngFor
loop to traverse all the columns defined inside the displayColumns
array.
How to freeze starting columns?
The [sticky]
takes boolean value to freeze or unfreaze a perticular column. We have used the column index to decide which column to make as sticky. By assignign i<3 we made first two columns at 0th and 1st position as sticky.
How to freeze end columns of datatable?
Similary the [stickyEnd]
starts from end to freeze the end columns stardting from end. For [stickyEnd] we assigned i > displayColumns.length-3 to freeze last two columns of table.
How to freeze header and footer rows in datatable?
The <mat-row>
with mat-header-row
and mat-footer-row
have the sticky:true which is making both header and footer rows as sticky. You can similarly assing any custom login to return boolean value to decide their sticky behaviour.
Step 5) Update Class/ Create Generate Dynamic Data
Now, move to the component class, that will have similar code we usually add to create datatable. We have used the for loop to dynamically create Columns and its Rows. But in real scenarios the data may code from remote services.
Update the app.component.ts file with following code:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
displayedColumns: any[] = [];
dataSource: any[] = [];
constructor() {
// Generate columns
for (let c = 0; c < 25; c++) {
this.displayedColumns.push('Column_' + c);
}
// Generate rows
for (let r = 0; r < 25; r++) {
const row: any = new Object();
for (let c = 0; c < 25; c++) {
row[this.displayedColumns[c]] = 'Row_' + c;
}
this.dataSource.push(row);
}
console.log(this.displayedColumns);
console.log(this.dataSource);
}
}
Step 6) Update CSS Style for Sticky
Most importantly you need to add the cell min-width, otherwise the mat-table sticky behaviour may not work properly. It works as expected even without min-width in case you use th native table tags.
Open the app.component.css file and following style:
.table-container {
height: 400px;
overflow: auto;
}
.mat-table-sticky {
background: #c7ffe4;
opacity: 1;
}
.mat-header-cell,
.mat-footer-cell,
.mat-cell {
min-width: 80px;
box-sizing: border-box;
}
.mat-header-row,
.mat-footer-row,
.mat-row {
min-width: 1920px;
}
Step 7) See In Action
Finally, run your application by hitting the npm start command to open application at default 4200 port at following URL: