Multiple expandable / collapsible rows in angular material table


Hey guys, in this post we are going to see how to make expandable/collapsible rows with the angular material table. Angular material table already provided us a solution for expandable/collapsible rows but, at a time we can expand only one row. So here we are going to see how to expand/collapse multiple rows at the same time, and very important is without installing any third-party package or tool.  Let’s do it step by step.

[You can download the project on the link given below at the end of the page]
[If you have any problem related to the Angular material table please check our following posts:
Click here for a simple material table with searching, sorting, and pagination,
Click here for inline editing and validation with template-driven forms in the angular material table,
Click here for add/remove columns dynamically in the angular material table,

Click here for a table inside a row and multiple paginators in the angular material table]

At the HTML side, we have created one material table to show the data of a student and added an expandable row after completing all columns definition. Here we have everything the same as angular material table expandable row, but we have changed the way, how the expandable row expands and how it gets data.

We have added separate field in student object to maintain the state of row (expanded/collapsed) and applied an expanded and collapsed class based on state. You can check the following HTML for the same.


app.component.html
<div class="row">
    <div class="col-12 text-center">
        <label for="Heading" class="form-control">
            Multiple expandable / collapseble rows - angular Material Table
        </label>
    </div>
</div>
<div class="row justify-content-center">
    <div class="col-8">
        <div class="example-container mat-elevation-z8">
            <mat-table #table [dataSource]="dataSource" multiTemplateDataRows>

                <!-- Expand Column -->
                <ng-container matColumnDef="expand">
                    <mat-header-cell *matHeaderCellDef> Expand </mat-header-cell>
                    <mat-cell *matCellDef="let element">
                        <span *ngIf="!element.isExpanded" class="signs">+</span>
                        <span *ngIf="element.isExpanded" class="signs">-</span>
                    </mat-cell>
                </ng-container>

                <!-- Roll No Column -->
                <ng-container matColumnDef="rollNo">
                    <mat-header-cell *matHeaderCellDef> Roll No </mat-header-cell>
                    <mat-cell *matCellDef="let element"> {{element.rollNo}} </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>

                <!-- Marks Column -->
                <ng-container matColumnDef="marks">
                    <mat-header-cell *matHeaderCellDef> Marks </mat-header-cell>
                    <mat-cell *matCellDef="let element"> {{element.marks}} </mat-cell>
                </ng-container>

                <!-- Standard Column -->
                <ng-container matColumnDef="standard">
                    <mat-header-cell *matHeaderCellDef> Standard </mat-header-cell>
                    <mat-cell *matCellDef="let element"> {{element.standard}} </mat-cell>
                </ng-container>

                <!-- Expanded Content Column - The detail row is made up of this one column -->
                <ng-container matColumnDef="expandedDetail">
                    <mat-cell *matCellDef="let detail">
                        <p>hey this is expanded block
                            You can Put here any static content as well as dynamic content</p>
                    </mat-cell>
                </ng-container>

                <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
                <mat-row *matRowDef="let row; columns: displayedColumns;" matRipple class="element-row"
                    [class.expanded]="row.isExpanded" (click)="expandCollapse(row)"></mat-row>
                <mat-row *matRowDef="let row; columns: ['expandedDetail'];"
                    [@detailExpand]="row.isExpanded == true ? 'expanded' : 'collapsed'" style="overflow: hidden">
                </mat-row>
            </mat-table>
        </div>
    </div>
</div>

In typescript file we have first defined student’s blueprint/structure to hold the data and added isExpanded an extra variable to manage the state. Here we can have multiple ways to manage the same, we can add an extra variable or we can create a separate array to hold the state of each row, but we choose to add extra variable because it is less confusing and easy to use.   
Then added some data of student and bonded with the material table.
Here we have just written a one function which changes the state of a row from collapsed to expanded and expanded to collapsed. You can check following ts file for the same.
app.component.ts
import { Component } from '@angular/core';
import { triggerstatestyletransitionanimate } from '@angular/animations';
import { MatTableDataSource } from '@angular/material';

export interface Student {
  rollNonumber;
  namestring;
  marksnumber;
  standardstring;
  isExpandedboolean;
}

const dataStudent[] = [
  { isExpanded: falserollNo: 1name: 'Ramesh'marks: 78standard: '10' },
  { isExpanded: falserollNo: 2name: 'Suresh'marks: 56standard: '12' },
  { isExpanded: falserollNo: 3name: 'Adi'marks: 77standard: '7' },
  { isExpanded: falserollNo: 4name: 'Rina'marks: 57standard: '9' },
  { isExpanded: falserollNo: 5name: 'Tapil'marks: 66standard: '9' },
  { isExpanded: falserollNo: 6name: 'Sugul'marks: 88standard: '5' },
  { isExpanded: falserollNo: 7name: 'Aftar'marks: 46standard: '5' },
  { isExpanded: falserollNo: 8name: 'Oxa'marks: 57standard: '5' },
  { isExpanded: falserollNo: 9name: 'Tam'marks: 76standard: '5' },
  { isExpanded: falserollNo: 10name: 'Luis'marks: 87standard: '7' }
];

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  animations: [
    trigger('detailExpand', [
      state('collapsed'style({ height: '0px'minHeight: '0'visibility: 'hidden' })),
      state('isExpanded'style({ height: '*'visibility: 'visible' })),
      transition('isExpanded <=> collapsed'animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
    ]),
  ],
})

export class AppComponent {
  displayedColumns = ['expand''rollNo''name''marks''standard'];
  dataSource = new MatTableDataSource<Student>();

  constructor() {
    this.dataSource.data = data;
  }

  expandCollapse(row) {
    if (row.isExpanded) {
      row.isExpanded = false;
    } else {
      row.isExpanded = true;
    }
  }

}


Small CSS code to make +, - button bold and large.

app.component.css
.signs{
    font-weightbolder;
    font-sizelarge;
}


Here is the sample output screenshot



That’s it, we have successfully implemented a demo for multiple expandable/collapsible rows in the angular material table. Hope you like it. 

Here is the demo
[download the demo]

[ If you are preparing for an interview please click here - angular interview questions and answers ]

Comments