Row spanning in Angular TreeGrid component

5 Sep 202522 minutes to read

The TreeGrid provides an option to span row cells, allowing merging two or more cells in a row into a single cell. This feature can be useful in scenarios where information needs to be displayed that spans across multiple rows, but repeating the same information in each row should be avoided.

To achieve this, define the rowSpan attribute to span cells in the queryCellInfo event. The rowSpan attribute is used to specify the number of rows that the current cell should span.

The queryCellInfo event is triggered for each cell in the TreeGrid, and allows customizing the cells in the TreeGrid. By handling this event, the rowSpan attribute can be set for a cell to achieve row spanning.

In the following demo, Lunch Break cell is spanned to two rows in the 1:00 column.

import { NgModule, ViewChild } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { TreeGridModule } from '@syncfusion/ej2-angular-treegrid'
import { Component, OnInit } from '@angular/core';
import { QueryCellInfoEventArgs, GridLine, Column } from '@syncfusion/ej2-angular-grids';
import { columnSpanData } from './datasource';
import { EmitType } from '@syncfusion/ej2-base';

@Component({
    imports: [TreeGridModule,],
    standalone: true,
    selector: 'app-container',
    template: `<ejs-treegrid [dataSource]='data' [height]='300' [width]='width' [gridLines]='gridLines' childMapping="subtasks" [treeColumnIndex]='1' 
       [allowTextWrap]='textWrap' (queryCellInfo)='queryCellInfoEvent($event)'>
        <e-columns>
            <e-column field='EmployeeID' headerText='Employee ID' width='150' textAlign="Right" isPrimaryKey=true></e-column>
            <e-column field='EmployeeName' headerText='Employee Name' width='200'></e-column>
            <e-column field='9:00' headerText='9:00 AM' width='120'></e-column>
            <e-column field='9:30' headerText='9:30 AM' width='120'></e-column>
            <e-column field='10:00' headerText='10:00 AM' width='120'></e-column>
            <e-column field='10:30' headerText='10:30 AM' width='120'></e-column>
            <e-column field='11:00' headerText='11:00 AM' width='120'></e-column>
            <e-column field='11:30' headerText='11:30 AM' width='120'></e-column>
            <e-column field='12:00' headerText='12:00 PM' width='120'></e-column>
            <e-column field='12:30' headerText='12:30 PM' width='120'></e-column>
            <e-column field='1:00' headerText='1:00 PM' width='120'></e-column>
            <e-column field='1:30' headerText='1:30 PM' width='120'></e-column>
            <e-column field='2:00' headerText='2:00 PM' width='120'></e-column>
            <e-column field='2:30' headerText='2:30 PM' width='120'></e-column>
            <e-column field='3:00' headerText='3:00 PM' width='120'></e-column>
            <e-column field='3:30' headerText='3:30 PM' width='120'></e-column>
            <e-column field='4:00' headerText='4:00 PM' width='120'></e-column>
            <e-column field='4:30' headerText='4:30 PM' width='120'></e-column>
            <e-column field='5:00' headerText='5:00 PM' width='120'></e-column>
        </e-columns>
    </ejs-treegrid>`,
})
export class AppComponent implements OnInit {
    public data?: object[];
    public width?: string | number;
    public gridLines?: GridLine;
    public textWrap?: boolean;
    public queryCellInfoEvent: EmitType<QueryCellInfoEventArgs> = (
        args: QueryCellInfoEventArgs
    ) => {
        const data: any = args.data as any;
        switch (data.EmployeeID) {
            case 10001:
                if (
                    (args.column as Column as Column).field === '9:00' ||
                    (args.column as Column).field === '2:30' ||
                    (args.column as Column).field === '4:30'
                ) {
                    args.colSpan = 2;
                } else if ((args.column as Column).field === '11:00') {
                    args.colSpan = 3;
                } else if ((args.column as Column).field === '1:00') {
                    args.rowSpan = 2;
                }
                break;
            case 10002:
                if (
                    (args.column as Column).field === '9:30' ||
                    (args.column as Column).field === '2:30' ||
                    (args.column as Column).field === '4:30'
                ) {
                    args.colSpan = 3;
                } else if ((args.column as Column).field === '11:00') {
                    args.colSpan = 4;
                }
                break;
            case 10003:
                if (
                    (args.column as Column).field === '9:00' ||
                    (args.column as Column).field === '11:30'
                ) {
                    args.colSpan = 3;
                } else if (
                    (args.column as Column).field === '10:30' ||
                    (args.column as Column).field === '3:30' ||
                    (args.column as Column).field === '4:30' ||
                    (args.column as Column).field === '2:30'
                ) {
                    args.colSpan = 2;
                }
                break;
            case 10004:
                if ((args.column as Column).field === '9:00') {
                    args.colSpan = 3;
                } else if ((args.column as Column).field === '11:00') {
                    args.colSpan = 4;
                } else if (
                    (args.column as Column).field === '4:00' ||
                    (args.column as Column).field === '2:30'
                ) {
                    args.colSpan = 2;
                }
                break;
            case 10005:
                if ((args.column as Column).field === '9:00') {
                    args.colSpan = 4;
                } else if ((args.column as Column).field === '11:30') {
                    args.colSpan = 3;
                } else if (
                    (args.column as Column).field === '3:30' ||
                    (args.column as Column).field === '4:30' ||
                    (args.column as Column).field === '2:30'
                ) {
                    args.colSpan = 2;
                }
                break;
            case 10006:
                if (
                    (args.column as Column).field === '9:00' ||
                    (args.column as Column).field === '4:30' ||
                    (args.column as Column).field === '2:30' ||
                    (args.column as Column).field === '3:30'
                ) {
                    args.colSpan = 2;
                } else if (
                    (args.column as Column).field === '10:00' ||
                    (args.column as Column).field === '11:30'
                ) {
                    args.colSpan = 3;
                }
                break;
            case 10007:
                if (
                    (args.column as Column).field === '9:00' ||
                    (args.column as Column).field === '3:00' ||
                    (args.column as Column).field === '10:30'
                ) {
                    args.colSpan = 2;
                } else if (
                    (args.column as Column).field === '11:30' ||
                    (args.column as Column).field === '4:00'
                ) {
                    args.colSpan = 3;
                }
                break;
            case 10008:
                if (
                    (args.column as Column).field === '9:00' ||
                    (args.column as Column).field === '10:30' ||
                    (args.column as Column).field === '2:30'
                ) {
                    args.colSpan = 3;
                } else if ((args.column as Column).field === '4:00') {
                    args.colSpan = 2;
                }
                break;
            case 10009:
                if (
                    (args.column as Column).field === '9:00' ||
                    (args.column as Column).field === '11:30'
                ) {
                    args.colSpan = 3;
                } else if (
                    (args.column as Column).field === '4:30' ||
                    (args.column as Column).field === '2:30'
                ) {
                    args.colSpan = 2;
                }
                break;
            case 100010:
                if (
                    (args.column as Column).field === '9:00' ||
                    (args.column as Column).field === '2:30' ||
                    (args.column as Column).field === '4:00' ||
                    (args.column as Column).field === '11:30'
                ) {
                    args.colSpan = 3;
                } else if ((args.column as Column).field === '10:30') {
                    args.colSpan = 2;
                }
                break;
        }
    };
    ngOnInit(): void {
        this.data = columnSpanData;
        this.gridLines = 'Both';
        this.width = 'auto';
        this.textWrap = true;
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

  • To disable the spanning for particular TreeGrid page, use requestType from queryCellInfo event argument.
  • The rowSpan and colSpan attributes can be used together to merge cells both vertically and horizontally.

Limitations

  • The updateCell method does not support row spanning.
  • Row spanning is not compatible with the following features:
    1. Virtual scrolling
    2. Infinite scrolling
    3. Row drag and drop
    4. Autofill
    5. Row or cell editing
    6. Batch editing
    7. CRUD