angulartypescriptangular-materialmat-tableangular-material-table

Expanding multiple rows in a nested mat table in Angular not working


I have created a nested mat-table grid using Angular Material. But currently only 1 row gets expanded at a time. I want to add a feature so that multiple rows can be expanded at a time, without the previous one getting collapsed.

Working Stackblitz link for Nested Table - https://stackblitz.com/edit/angular-nested-mat-table

Tried pushing elements to ExpandedElement Array but that didn't work much -

const index = this.expandedElements.findIndex(x => x.name == row.name);
if (index === -1) {
  this.expandedElements.push(row);
} else {
  this.expandedElements.splice(index, 1);
}

Can anyone help me on how to add multiple row expansion in this?


Solution

  • The expand/collapse logic is quite similar as in the answer for How to expand multiple rows in a Mat Table on clicking of a row in Angular?.

    Concepts (TL;DR)

    1. toggleElement function to Add element to expandedElement.
    2. isExpanded function to Check element is existed in expandedElement.
    3. Display element (is expanded/collapsed) with isExpanded.

    SOLUTION

    Previous

    <div class="example-element-detail" *ngIf="element.addresses?.data.length" [@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
      <div class="inner-table mat-elevation-z8" *ngIf="expandedElement">
    
    <tr mat-row *matRowDef="let element; columns: columnsToDisplay;" [class.example-element-row]="element.addresses?.data.length"
         [class.example-expanded-row]="expandedElement === element" (click)="toggleRow(element)">
    </tr>
    

    As the element is added into expandedElements to represent it is expanded, thus you need to check whether the element is in the expandedElements with isExpanded(element).

    Latest

    <div class="example-element-detail" *ngIf="element.addresses?.data.length" [@detailExpand]="isExpanded(element)">
      <div class="inner-table mat-elevation-z8" *ngIf="isExpanded(element)">
    
    <tr mat-row *matRowDef="let element; columns: columnsToDisplay;" [class.example-element-row]="element.addresses?.data.length"
         [class.example-expanded-row]="isExpanded(element)" (click)="toggleRow(element)">
    </tr>
    

    .component.ts

    export class TableExpandableRowsExample {
    
      ...
    
      expandedElements: any[] = [];
    
      ...
    
      toggleRow(element: User) {
        element.addresses && (element.addresses as MatTableDataSource<Address>).data.length 
          ? this.toggleElement(element) 
          : null;
        this.cd.detectChanges();
        this.innerTables.forEach((table, index) => (table.dataSource as MatTableDataSource<Address>).sort = this.innerSort.toArray()[index]);
      }
    
      isExpanded(row: User): string {
        const index = this.expandedElements.findIndex(x => x.name == row.name);
        if (index !== -1) {
          return 'expanded';
        }
        return 'collapsed';
      }
    
      toggleElement(row: User){
        const index = this.expandedElements.findIndex(x => x.name == row.name);
        if (index === -1) {
          this.expandedElements.push(row);
        } else {
          this.expandedElements.splice(index, 1);
        }
      }
    }
    

    Sample Solution on StackBlitz