Mat-table multiple row within a multiple row

Viewed 2511

What I want is drawn out in the following image. I use Angular Material (7.x) and use the Mat-Table implementation as described here: https://material.angular.io/components/table/overview

enter image description here

The above scenario is for the business to show multiple Sales Invoices.

I used Mat Table of Angular already for using multipe rows for one row, and this works. But now I also have to make the first row (Type A) have multiple rows within the multiple row table.

I have some ideas on how to be able to get this working, but I don't want to start and know beforehand if the solution is going to work or not.

I started iterating over the objects in the salesInvoices:

  <tr mat-header-row *matHeaderRowDef="displayedPurchaseInvoiceColumns"></tr>
  <ng-container *ngFor="let item of invoices.salesInvoice">
    <tr mat-row class="table-first-row" *matRowDef="let row; columns: displayedSalesInvoiceColumns"></tr>
  </ng-container>
  <tr mat-row class="table-second-row" *matRowDef="let row; columns: displayedPurchaseInvoiceColumns"></tr>

This doesn't show anything useful. I think it doesn't even do anything as I only see the purchase Invoices displayed, not the sales invoices.

I was thinking about using a mat-table for the first row? I have no idea how I am able to do so though, I am also not sure if this will work.

I really want to get this working WITH Mat-Table but I am afraid I won't be able to get it working with the library of Material and have to make something custom.

Any help is welcome! If I need to provide more information, please tell me.

1 Answers

You can create a two-level nested Mat-table in Angular in which it can expand multiple rows at a time. On each row click from the parent grid it calls an API and loads the data for the inner grid.

Component Code:

ngOnInit() {
    this.tableService.getData().subscribe(res => {
      if (res.length == 0) {
        this.panelDataSource = new MatTableDataSource();
      } else {
        console.log(res);
        this.panelDataSource = new MatTableDataSource(res);
      }
    });
  }

  getDetails(element: any) {
    
    this.tableService.getInnerData(element.Id).subscribe(res => {
      if (res.length == 0) {
        element['innerDatasource'] = new MatTableDataSource();
      } else {
        
        element['innerDatasource'] = new MatTableDataSource(res);
      }
    });
  }
}

HTML Code:

<table mat-table [dataSource]="panelDataSource" multiTemplateDataRows matSort>
    <ng-container [matColumnDef]="column" *ngFor="let column of columnsToDisplay">
        <th mat-header-cell *matHeaderCellDef> {{column}} </th>
        <td mat-cell (click)="getDetails(element)" *matCellDef="let element"> {{element[column]}} </td>
    </ng-container>

    <ng-container matColumnDef="expandedDetail">
        <td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplay.length">
            <div class="example-element-detail" [@detailExpand]="element?.expanded" *ngIf="element?.expanded">
                <div style="width: 100%;">

                    <table mat-table [dataSource]="element.innerDatasource" multiTemplateDataRows matSort>
                        <ng-container matColumnDef="{{innerColumn}}" *ngFor="let innerColumn of innerDisplayedColumns">
                            <th mat-header-cell *matHeaderCellDef mat-sort-header> {{innerColumn}} </th>
                            <td mat-cell *matCellDef="let address"> {{address[innerColumn]}} </td>
                        </ng-container>

                        <tr mat-header-row *matHeaderRowDef="innerDisplayedColumns"></tr>
                        <tr mat-row *matRowDef="let address; columns: innerDisplayedColumns;"
                            [class.example-element-row]="address.comments?.length" [class.example-expanded-row]="address?.expanded"
                            (click)="address.expanded = !address?.expanded">
                        </tr>
                    </table>
                </div>
            </div>
        </td>
    </ng-container>

    <tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
    <tr mat-row *matRowDef="let element; columns: columnsToDisplay;"
        [class.example-element-row]="element.addresses?.length" [class.example-expanded-row]="element?.expanded"
        (click)="element.expanded = !element?.expanded">
    </tr>
    <tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
</table>

Working Stackblitz

Related