Tree Column in Angular Gantt component

5 Apr 202524 minutes to read

The Syncfusion® Angular Gantt component provides a convenient way to represent parent-child relationships using expand and collapse icons in the tree column cell. This can be achieved by utilizing the treeColumnIndex property by setting its value to a column index. This guide outlines how to configure and use this property to display the expand or collapse icon in the desired column.

<ejs-gantt [dataSource]='data' [treeColumnIndex]='2'>
    <!-- Other gantt configurations -->
</ejs-gantt>

Change expand and collapse icon

The Syncfusion® Angular Gantt component allows to customize the default expand and collapse icons by applying custom CSS styles.

To customize the expand and collapse icons, use the following CSS styles:

.e-gantt .e-grid .e-treegridexpand::before {
  content: "\2795";
} 
.e-gantt .e-grid .e-treegridcollapse::before {
  content: "\2796";
}

In the following demo, the expand and collapse icons are customized using the CSS styles

import { BrowserModule } from '@angular/platform-browser';
import { GanttModule } from '@syncfusion/ej2-angular-gantt';

import { Component, ViewEncapsulation, ViewChild, OnInit, NgModule } from '@angular/core';
import { GanttComponent } from '@syncfusion/ej2-angular-gantt';
import { GanttData } from './data';

@Component({
    imports: [
         GanttModule
    ],
standalone: true,
    selector: 'app-root',
    template:
        `<ejs-gantt id="ganttDefault" #gantt height="430px"  [dataSource]="data" 
        [taskFields]="taskSettings" [treeColumnIndex]='1' [splitterSettings] = "splitterSettings" >        
            <e-columns>
                <e-column field='TaskID' headerText='Task ID' width=90 ></e-column>
                <e-column field='TaskName' headerText='Task Name' width=290></e-column>
                <e-column field='StartDate' headerText='Start Date' width=120 ></e-column>
                <e-column field='Duration' headerText='Duration'  width=90 ></e-column>
                <e-column field='Progress' headerText='Progress' width=120></e-column>
            </e-columns>
       </ejs-gantt>`,
    styleUrls: ['./app.component.css'],
    encapsulation: ViewEncapsulation.None
})
export class AppComponent {
    // Data for Gantt
    public data?: object[];
    @ViewChild('gantt')
    public gantt?: GanttComponent;
    public taskSettings?: object;
    public splitterSettings?: object;
    public cssClass: string = "custom";
    public ngOnInit(): void {
        this.data = GanttData;
        this.taskSettings = {
            id: 'TaskID',
            name: 'TaskName',
            startDate: 'StartDate',
            duration: 'Duration',
            progress: 'Progress',
            child: 'subtasks'
        };
        this.splitterSettings = {
            position: '75%'
        };
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
.e-gantt .e-grid .e-treegridexpand::before {
  content: "\2795";
} 
.e-gantt .e-grid .e-treegridcollapse::before {
  content: "\2796";
}

Change indent space of tree column cell text

The Gantt component allows to customize the indent space of tree column cell text by leveraging the queryCellInfo event.

In the following demonstration, indent space is applied by adding a CSS class to the tree column cell using the queryCellInfo event.

import { BrowserModule } from '@angular/platform-browser';
import { GanttModule } from '@syncfusion/ej2-angular-gantt';

import { Component, ViewEncapsulation, ViewChild, OnInit, NgModule } from '@angular/core';
import { GanttComponent } from '@syncfusion/ej2-angular-gantt';
import { GanttData } from './data';

@Component({
    imports: [
         GanttModule
    ],
standalone: true,
    selector: 'app-root',
    template:
        `<ejs-gantt id="ganttDefault" #gantt height="430px"  [dataSource]="data" [treeColumnIndex]='1'
        [taskFields]="taskSettings"  [splitterSettings] = "splitterSettings" (queryCellInfo)=querycellinfo($event)>             
        <e-columns>
            <e-column field='TaskID' headerText='Task ID' width=90 ></e-column>
            <e-column field='TaskName' headerText='Task Name' width=290></e-column>
            <e-column field='StartDate' headerText='Start Date' width=120 ></e-column>
            <e-column field='Duration' headerText='Duration' width=90 ></e-column>
            <e-column field='Progress' headerText='Progress' width=120></e-column>
        </e-columns>
       </ejs-gantt>`,
    styles: [
        `.indents {
            text-indent: 20px !important;
          }`
    ],
    encapsulation: ViewEncapsulation.None
})
export class AppComponent {
    // Data for Gantt
    public data?: object[];
    @ViewChild('gantt')
    public gantt?: GanttComponent;
    public taskSettings?: object;
    public splitterSettings?: object;
    public ngOnInit(): void {
        this.data = GanttData;
        this.taskSettings = {
            id: 'TaskID',
            name: 'TaskName',
            startDate: 'StartDate',
            duration: 'Duration',
            progress: 'Progress',
            child: 'subtasks'
        };
        this.splitterSettings = {
            position: '75%'
        };
    }
    querycellinfo(args: any): void {
        if (!args.data.hasChildRecords && args.column.index == (this.gantt as GanttComponent).treeColumnIndex) {
            args.cell.classList.add('indents');
        }
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Render parent rows in collapsed state

You can easily render all the parent rows in a collapsed state in the Gantt component using the collapseAllParentTasks property. Using this property, all parent rows are collapsed during the initial rendering.

In the following demo, all parent rows are rendered in collapsed state in initial rendering.

import { BrowserModule } from '@angular/platform-browser';
import { GanttModule } from '@syncfusion/ej2-angular-gantt';

import { Component, ViewEncapsulation, ViewChild, OnInit, NgModule } from '@angular/core';
import { GanttComponent } from '@syncfusion/ej2-angular-gantt';
import { GanttData } from './data';

@Component({
    imports: [
         GanttModule
    ],
standalone: true,
    selector: 'app-root',
    template:
        `<ejs-gantt id="ganttDefault" #gantt height="410px"  [dataSource]="data" 
            [taskFields]="taskSettings" [treeColumnIndex]='1' [splitterSettings] = "splitterSettings" [collapseAllParentTasks]="true">
            <e-columns>
                <e-column field='TaskID' headerText='Task ID' width=90 ></e-column>
                <e-column field='TaskName' headerText='Task Name' width=290></e-column>
                <e-column field='StartDate' headerText='Start Date' width=120 ></e-column>
                <e-column field='Duration' headerText='Duration' width=90 ></e-column>
                <e-column field='Progress' headerText='Progress' width=120></e-column>
            </e-columns>
        </ejs-gantt>`,
    encapsulation: ViewEncapsulation.None
})
export class AppComponent {
    // Data for Gantt
    public data?: object[];
    @ViewChild('gantt')
    public gantt?: GanttComponent;
    public taskSettings?: object;
    public splitterSettings?: object;
    public ngOnInit(): void {
        this.data = GanttData;
        this.taskSettings = {
            id: 'TaskID',
            name: 'TaskName',
            startDate: 'StartDate',
            duration: 'Duration',
            progress: 'Progress',
            child: 'subtasks'
        };
        this.splitterSettings = {
            position: '75%'
        };
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Retain expanded and collapsed state

To maintain the expanded and collapsed state of specific parent rows in the Syncfusion® Angular Gantt, utilize the expandState property. This property corresponds to a value within the data object of the data source, signifying the expand status of the parent row.

In the following demonstration, the parent rows are rendered in an expanded or collapsed state based on the value of the expandState property in the data source.

import { BrowserModule } from '@angular/platform-browser';
import { GanttModule } from '@syncfusion/ej2-angular-gantt';

import { Component, ViewEncapsulation, ViewChild, OnInit, NgModule } from '@angular/core';
import { GanttData } from './data';

@Component({
    imports: [
         GanttModule
    ],
standalone: true,
    selector: 'app-root',
    template:
        ` <ejs-gantt id="ganttDefault" height="430px" [dataSource]="data" [taskFields]="taskSettings" [treeColumnIndex]='1' [splitterSettings] = "splitterSettings">
                <e-columns>
                    <e-column field='TaskID' headerText='Task ID' textAlign='Right' width=90 ></e-column>
                    <e-column field='TaskName' headerText='Task Name' textAlign='Left' width=290></e-column>
                    <e-column field='StartDate' headerText='Start Date' textAlign='Right' width=120 ></e-column>
                    <e-column field='Duration' headerText='Duration' textAlign='Right' width=90 ></e-column>
                    <e-column field='Progress' headerText='Progress' textAlign='Right' width=120></e-column>
                </e-columns>
            </ejs-gantt>`,
    encapsulation: ViewEncapsulation.None
})
export class AppComponent {
    // Data for Gantt
    public data?: object[];
    public taskSettings?: object;
    public splitterSettings?: object;
    public ngOnInit(): void {
        this.data = GanttData;
        this.taskSettings = {
            id: 'TaskID',
            name: 'TaskName',
            startDate: 'StartDate',
            duration: 'Duration',
            progress: 'Progress',
            expandState: 'isExpand',
            child: 'subtasks'
        };
        this.splitterSettings = {
            position: '75%'
        };
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
export let GanttData: Object[] = [
    {
        TaskID: 1,
        TaskName: 'Project Initiation',
        StartDate: new Date('04/02/2019'),
        EndDate: new Date('04/21/2019'),
        isExpand: true,
        subtasks: [
            { TaskID: 2, TaskName: 'Identify Site location', StartDate: new Date('04/02/2019'), Duration: 4, Progress: 50, },
            { TaskID: 3, TaskName: 'Perform Soil test', StartDate: new Date('04/02/2019'), Duration: 4, Progress: 50, },
            {
                TaskID: 4,
                TaskName: 'Soil test approval',
                StartDate: new Date('04/02/2019'),
                Duration: 4,
                Progress: 50,
                isExpand: true,
                subtasks: [
                    {
                        TaskID: 5,
                        TaskName: 'Project Estimation',
                        StartDate: new Date('04/02/2019'),
                        EndDate: new Date('04/21/2019'),
                        isExpand: false,
                        subtasks: [
                            { TaskID: 6, TaskName: 'Develop floor plan for estimation', StartDate: new Date('04/04/2019'), Duration: 3, Progress: 50, },
                            { TaskID: 7, TaskName: 'List materials', StartDate: new Date('04/04/2019'), Duration: 3, Progress: 50, },
                            { TaskID: 8, TaskName: 'Estimation approval', StartDate: new Date('04/04/2019'), Duration: 3, Progress: 50, }
                        ]
                    },
                ]
            },
        ]
    },

];

Persist expanded and collapsed state on page refresh using localStorage

To persist the expanded and collapsed state of rows using the dataBound event when the page refreshes in the browser, this guide illustrates how to utilize localStorage to save and retrieve the state of rows.

  1. Save the collapsed record’s primarykey value to localStorage in the collapsed event of the Gantt by using the setItem method of the local storage.
  2. On page refresh, the dataBound event will be triggered. In that event, retrieve the saved records by using the getItem method of the local storage.
  3. Then, collapsed the specific rows by using the CollapseByKey method of treegrid object in gantt instance by passing the primary key value as a parameter. and collapse the specific rows by using the collapseRow method of the Tree Grid by passing the row detail.

In the following demo, the above-mentioned steps have been followed to persist the expanded or collapsed state while refreshing the page in the browser.

import { BrowserModule } from '@angular/platform-browser';
import { GanttModule } from '@syncfusion/ej2-angular-gantt';

import { Component, ViewEncapsulation, ViewChild, OnInit, NgModule } from '@angular/core';
import { GanttData } from './data';
import { GanttComponent } from '@syncfusion/ej2-angular-gantt';
@Component({
    imports: [
         GanttModule
    ],
standalone: true,
    selector: 'app-root',
    template:
        `<ejs-gantt id="ganttDefault" #gantt height="430px" [dataSource]="data" [taskFields]="taskSettings" [treeColumnIndex]='1'
        (dataBound)='dataBound()' (collapsed)="collapsed($event)" (expanded)="expanded($event)" [splitterSettings] = "splitterSettings"> 
            <e-columns>
                <e-column field='TaskID' headerText='Task ID' isPrimaryKey="true" textAlign='Right' width=90 ></e-column>
                <e-column field='TaskName' headerText='Name' textAlign='Left' width=290></e-column>
                <e-column field='StartDate' headerText='Start Date' textAlign='Right' width=120 ></e-column>
                <e-column field='Duration' headerText='Duration' textAlign='Right' width=90 ></e-column>
                <e-column field='Progress' headerText='Progress' textAlign='Right' width=120></e-column>
            </e-columns>
            </ejs-gantt>`,
    encapsulation: ViewEncapsulation.None
})
export class AppComponent {
    // Data for Gantt
    public data?: object[];
    @ViewChild('gantt')
    public gantt: GanttComponent | undefined;
    public taskSettings?: object;
    public splitterSettings?: object;
    public collapsingData: any = [];
    public ngOnInit(): void {
        this.data = GanttData;
        this.taskSettings = {
            id: 'TaskID',
            name: 'TaskName',
            startDate: 'StartDate',
            duration: 'Duration',
            progress: 'Progress',
            child: 'subtasks'
        };
        this.splitterSettings = {
            position: '75%'
        };
    }
    dataBound(): void {
        //checking whether it is initial rendering
        if ((this.gantt as GanttComponent).treeGrid.initialRender &&
            window.localStorage !== null
        ) {
            //retriving collapsed record in local storage using getItem method
            var Collapsed_storagedata = JSON.parse(
                window.localStorage.getItem('collapsingData') as any
            );

            if (Collapsed_storagedata !== null) {
                for (var i = 0; i < Collapsed_storagedata.length; i++) {
                    (this.gantt as GanttComponent).treeGrid.collapseByKey(
                        Collapsed_storagedata[i]
                    ); //collapsing row using collapseByKey method
                }
            }
        }
    }

    collapsed(args: any): void {
        //Here collected the collapsed record's primarykey value
        this.collapsingData.push((args.data as any).TaskID);

        //Here set/ update the localstorage value
        this.setstorage_data(this.collapsingData);
    }
    expanded(args: any): void {
        //Check whether the collapsing data array has the same primary key value as the expanding data.
        var index = this.collapsingData.findIndex((x: any) => {
            if (x == (args.data as any).TaskID) {
                return x;
            }
        });
        //if yes here we remove that primary key value
        this.collapsingData.splice(index, 1);

        // update the localstorage value
        this.setstorage_data(this.collapsingData);
    }
    setstorage_data(data: any): void {
        window.localStorage.setItem('collapsingData', JSON.stringify(data));
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Programmatically expand and collapse a row

In the Gantt, you can programmatically expand and collapse rows using various methods provided by the gantt. This guide demonstrates how to leverage these methods to control the expansion and collapse of rows based on different criteria.

To expand all rows in the gantt, use the expandAll method.

this.gantt.expandAll();

To collapse all rows in gantt, use the collapseAll method.

this.gantt.collapseAll();

To expand the records at a specific hierarchical level, use the expandAtLevel method.

this.gantt.treegrid.expandAtLevel(0);

To collapse the records at a specific hierarchical level, use the collapseAtLevel method.

this.gantt.treegrid.collapseAtLevel(0);

To expand records based on a given primary key value, use the expandByKey method.

this.gantt.treegrid.expandByKey(1); //Here pass the primary key value

To collapse records based on a given primary key value, use the collapseByKey method

this.gantt.treegrid.collapseByKey(1);//Here pass the primary key value

To expand child rows based on the row element, use the expandRow method.

this.gantt.treegrid.expandRow(tr); //Here pass the row element as parameter

To collapse child rows based on the row element, use the collapseRow method.

this.gantt.treegrid.collapseRow(tr);//Here pass the row element as parameter

Expand and collapse action events

In the Gantt, you can customize the behavior and perform specific actions when the expand or collapse icon is clicked. This can be achieved using a set of events provided by the gantt.

The following events are available for handling expand and collapse actions:

  • expanding: This event is triggered before a row is expanded. You can perform custom actions or cancel the row expansion based on certain conditions.

  • expanded: This event is triggered after a row is expanded. You can perform additional actions or updates after the row expansion is completed.

  • collapsing: This event is triggered before a row is collapsed. You can perform custom actions or cancel the row collapse based on certain conditions.

  • collapsed: This event is triggered after a row is collapsed. You can perform additional actions or updates after the row collapse is completed.

import { BrowserModule } from '@angular/platform-browser';
import { GanttModule } from '@syncfusion/ej2-angular-gantt';

import { Component, ViewEncapsulation, ViewChild, OnInit, NgModule } from '@angular/core';
import { GanttData } from './data';

@Component({
    imports: [
         GanttModule
    ],
standalone: true,
    selector: 'app-root',
    template:
        `<div class="control-section">
        <div style="margin-left:180px"><p style="color:red;" id="message"></p></div>
        <ejs-gantt id="ganttDefault" height="430px" [dataSource]="data" [taskFields]="taskSettings" [treeColumnIndex]='1' (expanding)="expanding($event)" (collapsing)="collapsing($event)" (collapsed)="collapsed($event)"
        (expanded)="expanded($event)" [splitterSettings] = "splitterSettings">
        <e-columns>
            <e-column field='TaskID' headerText='Task ID' textAlign='Right' width=90 ></e-column>
            <e-column field='TaskName' headerText='Task Name' textAlign='Left' width=290></e-column>
            <e-column field='StartDate' headerText='Start Date' textAlign='Right' width=120 ></e-column>
            <e-column field='Duration' headerText='Duration' textAlign='Right' width=90 ></e-column>
            <e-column field='Progress' headerText='Progress' textAlign='Right' width=120></e-column>
        </e-columns>
        </ejs-gantt>
       </div>`,
    encapsulation: ViewEncapsulation.None
})
export class AppComponent {
    // Data for Gantt
    public data?: object[];
    public taskSettings?: object;
    public splitterSettings?: object;
    public message?: string;
    public ngOnInit(): void {
        this.data = GanttData;
        this.taskSettings = {
            id: 'TaskID',
            name: 'TaskName',
            startDate: 'StartDate',
            endDate: 'EndDate',
            duration: 'Duration',
            progress: 'Progress',
            child: 'subtasks'
        };
        this.splitterSettings = {
            position: '75%'
        };
    }
    expanding(args: any): void {
        this.message = 'Expanding event is triggered';
    }
    collapsing(args: any): void {
        this.message = 'Collapsing event is triggered';
    }
    expanded(args: any): void {
        this.message = 'Expanded event is triggered';
    }
    collapsed(args: any): void {
        this.message = 'Collapsed event is triggered';
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));