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

13,523

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.

Share:
13,523
simple guy
Author by

simple guy

As a programmer I am still a newbie and that is why I created this account. ^^ In general, I am simple guy with simple wants and needs. But when I really want something I go and work for it.

Updated on June 07, 2022

Comments

  • simple guy
    simple guy almost 2 years

    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.

  • simple guy
    simple guy almost 5 years
    sorry, not what i was looking for. i want to merge cell horizontally not vertically.
  • shahnshah
    shahnshah over 3 years
    Amazing!!! this saved a ton of work for me, thanks a million
  • robs23
    robs23 over 3 years
    Thanks for it, works like a charm. I noticed, though, that it works correctly for first 3 columns, all further columns get spanColumnContext.spannnedRow = undefined. Perhaps you know why this is?
  • uminder
    uminder over 3 years
    @robs23: I had a look at the code I posted and noticed there was a problem. I updated/improved my answer accordingly.
  • robs23
    robs23 over 3 years
    You probably were targetting some other edge case, for me things didn't change a bit - it still doesn't work. I forked your example on stackblitz.com/edit/angular-table-row-span-gn6rnu?file=src/a‌​pp/… . If you have a chance, please check it out, I changed your data to the exact data I work with and no rows are merged
  • uminder
    uminder over 3 years
    @robs23: The RowSpanComputer class computes the rowspan for each cell out of the specified table data (array of rows). It basically loops over the rows and increments the rowspan for cells as long as their value remains unchanged and left located cells were also spanned. As soon as the value changes, the corresponding rowspan is reset to zero. I took a quick look to your code and see that the values in the first few columns are different for each row. Therefore no rowspan is applied at all. If you need a solution for your particular case, please post a new question.
  • robs23
    robs23 over 3 years
    Thanks. What I didn't catch was the fact that you have to provide columns ordered by rowspan descending.. I mean, If first column does not contain repeatable data (all values are unique in first column for all rows), rowspan will always be 1 for all next columns, regardless if there are any repeatable values there or not.. If I feed your function with column names in appropriate order, it will count rowspan correctly. And I can reorder them the way I want in the template anyway