Tree column in Angular Gantt component
18 Oct 202524 minutes to read
The Syncfusion® Angular Gantt component provides a structured way to display parent-child relationships using expand/collapse icons.
To configure this, set the treeColumnIndex property to the index of the column where these icons should appear. This enables clear visualization and navigation of hierarchical tasks within the Gantt chart.
<ejs-gantt [dataSource]='data' [treeColumnIndex]='2'>
<!-- Other gantt configurations -->
</ejs-gantt>Customize expand and collapse icons
The Syncfusion® Angular Gantt component provides support for customizing default expand/collapse icons through CSS.
To apply custom icons, override the default styles with the following CSS:
.e-gantt .e-grid .e-treegridexpand::before {
content: "\2795";
}
.e-gantt .e-grid .e-treegridcollapse::before {
content: "\2796";
}import { GanttModule } from '@syncfusion/ej2-angular-gantt';
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
import { GanttData } from './data';
@Component({
imports: [ GanttModule],
standalone: true,
selector: 'app-root',
template:
`<ejs-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 implements OnInit {
public data?: object[];
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%'
};
}
}.e-gantt .e-grid .e-treegridexpand::before {
content: "\2795";
}
.e-gantt .e-grid .e-treegridcollapse::before {
content: "\2796";
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));/**
* TreeGrid DataSource
*/
export let GanttData: Object[] = [
{
TaskID: 1,
TaskName: 'Project Initiation',
StartDate: new Date('04/02/2019'),
EndDate: new Date('04/21/2019'),
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 },
]
},
{
TaskID: 5,
TaskName: 'Project Estimation',
StartDate: new Date('04/02/2019'),
EndDate: new Date('04/21/2019'),
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 }
]
},
];Customize indentation of tree column text
The Syncfusion® Angular Gantt component allows customization of the indent space in tree column cells using the queryCellInfo event.
In the following demonstration, indentation is applied by dynamically adding a CSS class to the tree column cell of TaskName using the queryCellInfo event.
import { GanttModule } from '@syncfusion/ej2-angular-gantt';
import { Component, ViewEncapsulation, ViewChild, OnInit, NgModule } from '@angular/core';
import { GanttComponent, QueryCellInfoEventArgs } from '@syncfusion/ej2-angular-gantt';
import { GanttData } from './data';
import { Column } from '@syncfusion/ej2-grids';
@Component({
imports: [GanttModule],
standalone: true,
selector: 'app-root',
template:
`<ejs-gantt #gantt height="370px" [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: 80px !important;
}`
],
encapsulation: ViewEncapsulation.None
})
export class AppComponent implements OnInit {
@ViewChild('gantt') public ganttInstance?: GanttComponent;
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',
child: 'subtasks'
};
this.splitterSettings = {
position: '75%'
};
}
public querycellinfo(args: QueryCellInfoEventArgs): void {
const data = args.data as { hasChildRecords?: boolean };
const columnIndex = (args.column as Column).index;
const treeColumnIndex = this.ganttInstance?.treeColumnIndex;
if (!data.hasChildRecords && columnIndex === 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));/**
* TreeGrid DataSource
*/
export let GanttData: Object[] = [
{
TaskID: 1,
TaskName: 'Project Initiation',
StartDate: new Date('04/02/2019'),
EndDate: new Date('04/21/2019'),
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 },
]
},
{
TaskID: 5,
TaskName: 'Project Estimation',
StartDate: new Date('04/02/2019'),
EndDate: new Date('04/21/2019'),
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 }
]
},
];Render parent rows in collapsed state
You can collapse all parent rows during initial rendering by setting the collapseAllParentTasks property in the Gantt component.
import { GanttModule } from '@syncfusion/ej2-angular-gantt';
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
import { GanttData } from './data';
@Component({
imports: [ GanttModule],
standalone: true,
selector: 'app-root',
template:
`<ejs-gantt height="370px" [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 implements OnInit {
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',
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));/**
* TreeGrid DataSource
*/
export let GanttData: Object[] = [
{
TaskID: 1,
TaskName: 'Project Initiation',
StartDate: new Date('04/02/2019'),
EndDate: new Date('04/21/2019'),
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 },
]
},
{
TaskID: 5,
TaskName: 'Project Estimation',
StartDate: new Date('04/02/2019'),
EndDate: new Date('04/21/2019'),
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 }
]
},
];Retain expand/collapse state on initial load
You can retain the expanded or collapsed state of parent rows during initial rendering by using the expandState property in the data source. This property indicates whether a parent row should be expanded or collapsed when the Gantt component loads.
import { GanttModule } from '@syncfusion/ej2-angular-gantt';
import { Component, ViewEncapsulation, OnInit } 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 implements OnInit {
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, }
]
},
]
},
]
},
];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 expand/collapse state across page refresh using localStorage
To retain the expanded and collapsed state of rows after a page refresh in the Syncfusion® Angular Gantt component:
- Use the collapsed event to store the collapsed row’s primary key in
localStoragevia setItem. - On page reload, retrieve the stored keys in the dataBound event using getItem.
- Collapse the corresponding rows using
CollapseByKeyorcollapseRowmethods by passing the saved key or row details.
This approach ensures that row states are preserved across browser sessions, enhancing user experience and continuity.
In the following demo, the steps mentioned above are used to persist the expanded and collapsed state of rows during a browser page refresh.
import { GanttModule, ICollapsingEventArgs } from '@syncfusion/ej2-angular-gantt';
import { Component, ViewEncapsulation, ViewChild, OnInit } 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 #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 implements OnInit {
@ViewChild('gantt') public ganttInstance?: GanttComponent;
public data?: object[];
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%'
};
}
public dataBound(): void {
//checking whether it is initial rendering.
if ((this.ganttInstance 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.ganttInstance as GanttComponent).treeGrid.collapseByKey(
Collapsed_storagedata[i]
); //collapsing row using collapseByKey method.
}
}
}
}
public collapsed(args: ICollapsingEventArgs): 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);
}
public expanded(args: ICollapsingEventArgs): 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));/**
* TreeGrid DataSource
*/
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 },
]
},
{
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 }
]
},
];Programmatically expand or collapse rows
The Syncfusion® Angular Gantt component provides built-in methods to programmatically control row expansion and collapse:
- expandAll(): Expands all rows.
this.gantt.expandAll();- collapseAll(): Collapses all rows.
this.gantt.collapseAll();-
expandAtLevel(level): Expands rows at a specific level.
this.gantt.treegrid.expandAtLevel(0);-
collapseAtLevel(level): Collapses rows at a specific level.
this.gantt.treegrid.collapseAtLevel(0);-
expandByKey(key): Expands a row by primary key.
this.gantt.treegrid.expandByKey(1); //Here pass the primary key value.-
collapseByKey(key): Collapses a row by primary key.
this.gantt.treegrid.collapseByKey(1);//Here pass the primary key value.-
expandRow(rowElement): Expands a row using its DOM element.
this.gantt.treegrid.expandRow(tr); //Here pass the row element as parameter.-
collapseRow(rowElement): Collapses a row using its DOM element.
this.gantt.treegrid.collapseRow(tr);//Here pass the row element as parameter.Retrieve expanded records
To retrieve the currently expanded rows in the Gantt component, use the getExpandedRecords method.
import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { GanttModule, GanttComponent } from '@syncfusion/ej2-angular-gantt';
import { EditService, ToolbarService, SelectionService } from '@syncfusion/ej2-angular-gantt';
import { CommonModule } from '@angular/common';
import { DialogModule, DialogComponent } from '@syncfusion/ej2-angular-popups';
import { ClickEventArgs } from '@syncfusion/ej2-navigations';
import { GanttData } from './data';
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule, GanttModule, DialogModule],
providers: [ToolbarService, EditService, SelectionService],
template: `
<ejs-gantt #gantt height="370px" [dataSource]="data" [taskFields]="taskSettings" [treeColumnIndex]="1" [splitterSettings]="splitterSettings"
[collapseAllParentTasks]="true" [toolbar]="toolbar" (toolbarClick)="onToolbarClick($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>
<ejs-dialog #dialog width="400px" height="auto" header="Parent Tasks" [visible]="false" [showCloseIcon]="true" [isModal]="true">
<ng-template #content>
<div *ngIf="parentTasks.length > 0">
<ul>
<li *ngFor="let task of parentTasks">
Task ID: , Task Name:
</li>
</ul>
</div>
<div *ngIf="parentTasks.length === 0">
No parent tasks found.
</div>
</ng-template>
</ejs-dialog>`
})
export class AppComponent implements OnInit {
@ViewChild('gantt') public ganttInstance?: GanttComponent;
@ViewChild('dialog') public dialogObj?: DialogComponent;
public data?: object[];
public taskSettings?: object;
public splitterSettings?: object;
public toolbar: any[] = [];
public parentTasks: any[] = [];
ngOnInit(): void {
this.data = GanttData;
this.taskSettings = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
duration: 'Duration',
progress: 'Progress',
child: 'subtasks'
};
this.splitterSettings = {
position: '75%'
};
this.toolbar = [
'Add',
'Edit',
'Delete',
{ text: 'Show Expand Parent Tasks', id: 'show_parents', tooltipText: 'Show expand parent tasks in dialog' }
];
}
public onToolbarClick(args: ClickEventArgs): void {
if (args.item.id === 'show_parents' && this.ganttInstance && this.dialogObj) {
// Get expanded records from flatData
const expandedRecords = this.ganttInstance.getExpandedRecords(this.ganttInstance.flatData);
// Filter only parent tasks that are currently expanded.
this.parentTasks = expandedRecords
.filter((record: any) => record.hasChildRecords && record.expanded === true)
.map((record: any) => ({
TaskID: record.TaskID,
TaskName: record.TaskName
}));
this.dialogObj.show();
}
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));/**
* TreeGrid DataSource
*/
export let GanttData: Object[] = [
{
TaskID: 1,
TaskName: 'Project Initiation',
StartDate: new Date('04/02/2019'),
EndDate: new Date('04/21/2019'),
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 },
]
},
{
TaskID: 5,
TaskName: 'Project Estimation',
StartDate: new Date('04/02/2019'),
EndDate: new Date('04/21/2019'),
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 }
]
},
];Customize expand/collapse behavior using events
You can customize expand and collapse behavior in the Syncfusion® Angular Gantt component using the expanding, expanded, collapsing, and collapsed events. These events allow you to control and respond to row state changes programmatically based on your application logic.
The following sample demonstrates how to customize expand and collapse actions in the Syncfusion® Angular Gantt component:
- Expanding is canceled for the row where TaskID is 1.
- Collapsing is canceled for the row where TaskID is 5.
- When a row is expanded and its Progress is greater than 50, a green background is applied.
- When a row is collapsed and its Progress is less than 50, a red background is applied.
import { Component, ViewEncapsulation } from '@angular/core';
import { GanttModule, ICollapsingEventArgs } from '@syncfusion/ej2-angular-gantt';
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]="messageColor" 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 {
public data?: object[];
public taskSettings?: object;
public splitterSettings?: object;
public message: string = '';
public messageColor: string = 'black';
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%'
};
}
public expanding(args: ICollapsingEventArgs): void {
const data = args.data as IGanttTask | undefined;
if (data) {
this.message = `Expanding Task: ${data.TaskName} (ID: ${data.TaskID})`;
this.messageColor = 'blue';
if (data.TaskID === 1) {
args.cancel = true;
this.message = `Expanding cancelled for Task: ${data.TaskName} (ID: ${data.TaskID})`;
this.messageColor = 'red';
}
}
}
public collapsing(args: ICollapsingEventArgs): void {
const data = args.data as IGanttTask | undefined;
if (data) {
this.message = `Collapsing Task: ${data.TaskName} (ID: ${data.TaskID})`;
this.messageColor = 'orange';
if (data.TaskID === 5) {
args.cancel = true;
this.message = `Collapsing cancelled for Task: ${data.TaskName} (ID: ${data.TaskID})`;
this.messageColor = 'red';
}
}
}
public expanded(args: ICollapsingEventArgs): void {
const data = args.data as IGanttTask | undefined;
if (data && (args as any).row) {
this.message = `Task Expanded: ${data.TaskName} (ID: ${data.TaskID})`;
this.messageColor = 'green';
(args as any).row.style.background = '';
if ((data.Progress ?? 0) > 50) {
(args as any).row.style.background = '#c0f6c7ff';
}
}
}
public collapsed(args: ICollapsingEventArgs): void {
const data = args.data as IGanttTask | undefined;
if (data && (args as any).row) {
this.message = `Task Collapsed: ${data.TaskName} (ID: ${data.TaskID})`;
this.messageColor = 'purple';
(args as any).row.style.background = '';
if ((data.Progress ?? 0) < 50) {
(args as any).row.style.background = '#fb9c9cff';
}
}
}
}
export interface IGanttTask {
TaskID: number;
TaskName: string;
StartDate?: Date;
EndDate?: Date;
Duration?: number;
Progress?: number;
subtasks?: IGanttTask[];
}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'),
subtasks: [
{ TaskID: 2, TaskName: 'Identify Site location', StartDate: new Date('04/02/2019'), Duration: 4, Progress: 60 },
{ TaskID: 3, TaskName: 'Perform Soil test', StartDate: new Date('04/02/2019'), Duration: 4, Progress: 90 },
{ TaskID: 4, TaskName: 'Soil test approval', StartDate: new Date('04/02/2019'), Duration: 4, Progress: 70 },
{ TaskID: 9, TaskName: 'Environmental clearance', StartDate: new Date('04/03/2019'), Duration: 3, Progress: 50 }
]
},
{
TaskID: 5,
TaskName: 'Project Estimation',
StartDate: new Date('04/04/2019'),
EndDate: new Date('04/21/2019'),
subtasks: [
{ TaskID: 6, TaskName: 'Develop floor plan for estimation', StartDate: new Date('04/04/2019'), Duration: 3, Progress: 10 },
{ TaskID: 7, TaskName: 'List materials', StartDate: new Date('04/04/2019'), Duration: 3, Progress: 70 },
{ TaskID: 8, TaskName: 'Estimation approval', StartDate: new Date('04/04/2019'), Duration: 3, Progress: 20 },
{ TaskID: 10, TaskName: 'Budget review', StartDate: new Date('04/05/2019'), Duration: 2, Progress: 40 }
]
},
{
TaskID: 11,
TaskName: 'Design Phase',
StartDate: new Date('04/22/2019'),
EndDate: new Date('05/10/2019'),
subtasks: [
{ TaskID: 12, TaskName: 'Architectural design', StartDate: new Date('04/22/2019'), Duration: 5, Progress: 30 },
{ TaskID: 13, TaskName: 'Structural design', StartDate: new Date('04/23/2019'), Duration: 4, Progress: 50 },
{ TaskID: 14, TaskName: 'Electrical layout', StartDate: new Date('04/24/2019'), Duration: 3, Progress: 20 },
{ TaskID: 15, TaskName: 'Design approval', StartDate: new Date('04/25/2019'), Duration: 2, Progress: 10 }
]
},
{
TaskID: 16,
TaskName: 'Procurement',
StartDate: new Date('05/11/2019'),
EndDate: new Date('05/25/2019'),
subtasks: [
{ TaskID: 17, TaskName: 'Identify vendors', StartDate: new Date('05/11/2019'), Duration: 3, Progress: 60 },
{ TaskID: 18, TaskName: 'Request quotations', StartDate: new Date('05/12/2019'), Duration: 2, Progress: 40 },
{ TaskID: 19, TaskName: 'Vendor selection', StartDate: new Date('05/13/2019'), Duration: 2, Progress: 30 },
{ TaskID: 20, TaskName: 'Purchase materials', StartDate: new Date('05/14/2019'), Duration: 3, Progress: 20 }
]
},
{
TaskID: 21,
TaskName: 'Foundation Work',
StartDate: new Date('05/26/2019'),
EndDate: new Date('06/10/2019'),
subtasks: [
{ TaskID: 22, TaskName: 'Excavation', StartDate: new Date('05/26/2019'), Duration: 4, Progress: 50 },
{ TaskID: 23, TaskName: 'Foundation pouring', StartDate: new Date('05/30/2019'), Duration: 3, Progress: 40 },
{ TaskID: 24, TaskName: 'Curing', StartDate: new Date('06/02/2019'), Duration: 5, Progress: 30 },
{ TaskID: 25, TaskName: 'Inspection', StartDate: new Date('06/07/2019'), Duration: 2, Progress: 20 }
]
},
{
TaskID: 26,
TaskName: 'Structural Work',
StartDate: new Date('06/11/2019'),
EndDate: new Date('06/30/2019'),
subtasks: [
{ TaskID: 27, TaskName: 'Column construction', StartDate: new Date('06/11/2019'), Duration: 4, Progress: 60 },
{ TaskID: 28, TaskName: 'Beam construction', StartDate: new Date('06/15/2019'), Duration: 4, Progress: 50 },
{ TaskID: 29, TaskName: 'Slab casting', StartDate: new Date('06/19/2019'), Duration: 4, Progress: 40 },
{ TaskID: 30, TaskName: 'Structural inspection', StartDate: new Date('06/23/2019'), Duration: 3, Progress: 30 }
]
},
{
TaskID: 31,
TaskName: 'Roofing',
StartDate: new Date('07/01/2019'),
EndDate: new Date('07/15/2019'),
subtasks: [
{ TaskID: 32, TaskName: 'Roof frame setup', StartDate: new Date('07/01/2019'), Duration: 3, Progress: 20 },
{ TaskID: 33, TaskName: 'Sheet installation', StartDate: new Date('07/04/2019'), Duration: 3, Progress: 30 },
{ TaskID: 34, TaskName: 'Waterproofing', StartDate: new Date('07/07/2019'), Duration: 2, Progress: 40 },
{ TaskID: 35, TaskName: 'Roof inspection', StartDate: new Date('07/09/2019'), Duration: 2, Progress: 50 }
]
},
{
TaskID: 36,
TaskName: 'Interior Work',
StartDate: new Date('07/16/2019'),
EndDate: new Date('08/05/2019'),
subtasks: [
{ TaskID: 37, TaskName: 'Plastering', StartDate: new Date('07/16/2019'), Duration: 4, Progress: 30 },
{ TaskID: 38, TaskName: 'Painting', StartDate: new Date('07/20/2019'), Duration: 4, Progress: 40 },
{ TaskID: 39, TaskName: 'Flooring', StartDate: new Date('07/24/2019'), Duration: 4, Progress: 50 },
{ TaskID: 40, TaskName: 'Electrical fittings', StartDate: new Date('07/28/2019'), Duration: 3, Progress: 60 }
]
},
{
TaskID: 41,
TaskName: 'Final Inspection',
StartDate: new Date('08/06/2019'),
EndDate: new Date('08/15/2019'),
subtasks: [
{ TaskID: 42, TaskName: 'Safety check', StartDate: new Date('08/06/2019'), Duration: 2, Progress: 70 },
{ TaskID: 43, TaskName: 'Compliance review', StartDate: new Date('08/08/2019'), Duration: 2, Progress: 80 },
{ TaskID: 44, TaskName: 'Client walkthrough', StartDate: new Date('08/10/2019'), Duration: 2, Progress: 90 },
{ TaskID: 45, TaskName: 'Final approval', StartDate: new Date('08/12/2019'), Duration: 2, Progress: 100 }
]
},
{
TaskID: 46,
TaskName: 'Project Closure',
StartDate: new Date('08/16/2019'),
EndDate: new Date('08/25/2019'),
subtasks: [
{ TaskID: 47, TaskName: 'Documentation', StartDate: new Date('08/16/2019'), Duration: 2, Progress: 100 },
{ TaskID: 48, TaskName: 'Final billing', StartDate: new Date('08/18/2019'), Duration: 2, Progress: 100 },
{ TaskID: 49, TaskName: 'Feedback collection', StartDate: new Date('08/20/2019'), Duration: 2, Progress: 100 },
{ TaskID: 50, TaskName: 'Team debrief', StartDate: new Date('08/22/2019'), Duration: 2, Progress: 100 }
]
}
];