Angular mat-table: Is it possible to merge cells by columns?

simple guy picture simple guy · Jul 4, 2019 · Viewed 10.6k times · Source

I'm having trouble finding an answer on how to merge columns cells in mat-table. Only saw few examples in merging row cells using when. So was wondering if i can find answers here.

I have this JSON data:

{
    "id": 4,
    "description": "this is another block",
    "block_size": 3480,
    "lot_count": 5,
    "lots": [
        {
            "id": 17,
            "lot_name": "test 17",
            "status": "SOLD",
            "block_id": 4,
            "lot_id": 1,
            "lot_size": 828
        },
        {
            "id": 18,
            "lot_name": "test 18",
            "status": "OPEN",
            "block_id": 4,
            "lot_id": 2,
            "lot_size": 885
        },
        {
            "id": 19,
            "lot_name": "test 19",
            "status": "SOLD",
            "block_id": 4,
            "lot_id": 3,
            "lot_size": 648
        },
        {
            "id": 20,
            "lot_name": "test 20",
            "status": "OPEN",
            "block_id": 4,
            "lot_id": 4,
            "lot_size": 553
        },
        {
            "id": 21,
            "lot_name": "Test 21",
            "status": "OPEN",
            "block_id": 4,
            "lot_id": 5,
            "lot_size": 566
        }
    ]
}

And was expecting an output in mat-table as:

+------------------------------------------------------------------+
| No.        Lot Name    Block    Block Size    Lot Id    Lot Size |
+------------------------------------------------------------------+
| 17         test 17                            1         828      |
| 18         test 18                            2         885      |
| 19         test 19     4        3480          3         648      |
| 20         test 20                            4         553      |
| 21         test 21                            5         566      |
+------------------------------------------------------------------+

As you can see I want to make the cells in columns Block and Block Size to merge.

Answer

uminder picture uminder · Oct 7, 2019

Meanwhile you probably found a solution to your problem but since I just created the following StackBlitz, I share it in case someone else looks for a solution to the same issue.

https://stackblitz.com/edit/angular-gevqvq

The RowSpanComputer class from this solution is based on code found in the open source project Koia. In there, the computed rowspan attributes are used within summary-table.component.html.

UPDATE

The code example in the above linked StackBlitz works only for optimistic cases. Ideally no row spans are computed for the last table column, otherwise rows are not displayed if they are identical to the previous one.

ngOnInit() {
  this.columnNames = Object.keys(this.data[0]);
  this.lastColumnName = this.columnNames[this.columnNames.length - 1];
  this.allButLastColumnNames = this.columnNames.slice(0, -1);
  this.rowSpans = this.rowSpanComputer.compute(this.data, this.allButLastColumnNames);
}

In the HTML template this must also be taken into account. There we treat the preceding and the last column differently.

<table mat-table *ngIf="rowSpans" [dataSource]="data" class="mat-elevation-z8">
  <ng-container *ngFor="let columnName of allButLastColumnNames; let iCol = index" [matColumnDef]="columnName">
    <th mat-header-cell *matHeaderCellDef>{{ columnName }}</th>
    <td mat-cell *matCellDef="let row; let iRow = index" [attr.rowspan]="rowSpans[iCol][iRow].span"
       [style.display]="rowSpans[iCol][iRow].span === 0 ? 'none'  : ''">{{ row[columnName] }}</td>
  </ng-container>
  <ng-container [matColumnDef]="lastColumnName">
    <th mat-header-cell *matHeaderCellDef>{{ lastColumnName }}</th>
    <td mat-cell *matCellDef="let row; let iRow = index">{{ row[lastColumnName] }}</td>
  </ng-container>
  <tr mat-header-row *matHeaderRowDef="columnNames"></tr>
  <tr mat-row *matRowDef="let row; columns: columnNames"></tr>
</table>

Please take a look at this improved StackBlitz and see how it works.