Work Breakdown Structure (WBS) in React Gantt Chart
6 Aug 202624 minutes to read
The Work Breakdown Structure (WBS) organizes project tasks hierarchically by assigning unique codes to each task. This improves task visibility and management, especially in large-scale construction or enterprise-level software projects.
Configuration and implementation
To enable WBS in the Gantt Chart component:
- Enable WBS Codes: Set enableWBS to true to automatically generate unique task codes and define their predecessors.
- Auto-Update Codes: Set enableAutoWbsUpdate to true to maintain accurate WBS codes during operations such as sorting, editing, or drag-and-drop.
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, Inject, Selection, ColumnsDirective, ColumnDirective, Toolbar, DayMarkers, Edit, Filter, Sort, ContextMenu, EventMarkersDirective, EventMarkerDirective } from '@syncfusion/ej2-react-gantt';
import { WBSData } from './datasource';
function App() {
const taskFields = {
id: "TaskID",
name: "TaskName",
startDate: "StartDate",
endDate: "EndDate",
duration: "Duration",
progress: "Progress",
dependency: "Predecessor",
parentID: 'ParentID'
};
let ganttInstance;
const eventMarkerDay1 = new Date('04/02/2024');
const editSettings = {
allowAdding: true,
allowEditing: true,
allowDeleting: true,
allowTaskbarEditing: true,
showDeleteConfirmDialog: true,
};
const toolbar = ["Add", "Edit", "Update", "Delete", "Cancel", "ExpandAll", "CollapseAll"];
const timelineSettings = {
showTooltip: true,
topTier: {
unit: "Week",
format: "dd/MM/yyyy",
},
bottomTier: {
unit: "Day",
count: 1,
},
};
const labelSettings = {
taskLabel: '${Progress}%'
};
const projectStartDate = new Date("03/31/2024");
const projectEndDate = new Date("05/30/2024");
const splitterSettings = {
columnIndex: 4
};
const selectionSettings = {
mode: "Row",
type: "Single",
enableToggle: false,
};
const tooltipSettings = {
showTooltip: true,
};
const filterSettings = {
type: "Menu",
};
return <GanttComponent id="EnableWbs" taskFields={taskFields} ref={ganttInstance} toolbar={toolbar} treeColumnIndex={2} dataSource={WBSData} allowSorting={true} enableContextMenu={true} enableWBS={true} enableAutoWbsUpdate={true} editSettings={editSettings} allowSelection={true} allowPdfExport={true} splitterSettings={splitterSettings} selectionSettings={selectionSettings} tooltipSettings={tooltipSettings} filterSettings={filterSettings} timelineSettings={timelineSettings} highlightWeekends={true} allowFiltering={true} gridLines={"Both"} labelSettings={labelSettings} taskbarHeight={20} rowHeight={40} height={"550px"} allowUnscheduledTasks={true} projectStartDate={projectStartDate} projectEndDate={projectEndDate}>
<ColumnsDirective>
<ColumnDirective field="TaskID" visible={false} />
<ColumnDirective field="WBSCode" width='150px' />
<ColumnDirective field="TaskName" headerText="Task Name" allowReordering={false} width='260px' />
<ColumnDirective field="StartDate" headerText="Start Date" width='140px' />
<ColumnDirective field="WBSPredecessor" headerText="WBS Predecessor" width='190px' />
<ColumnDirective field="Duration" headerText="Duration" allowEditing={false} width='130px' />
<ColumnDirective field="Progress" headerText="Progress" />
</ColumnsDirective>
<EventMarkersDirective>
<EventMarkerDirective day={eventMarkerDay1} label='Project Initiation'></EventMarkerDirective>
</EventMarkersDirective>
<Inject services={[Selection, DayMarkers, Toolbar, Edit, Filter, Sort, ContextMenu]} />
</GanttComponent>
};
ReactDOM.render(<App />, document.getElementById('root'));import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, Inject, Selection, ColumnsDirective, ColumnDirective, Toolbar, DayMarkers, Edit, Filter, Sort, ContextMenu, EventMarkersDirective, EventMarkerDirective } from '@syncfusion/ej2-react-gantt';
import { WBSData } from './datasource';
function App() {
const taskFields = {
id: "TaskID",
name: "TaskName",
startDate: "StartDate",
endDate: "EndDate",
duration: "Duration",
progress: "Progress",
dependency: "Predecessor",
parentID: 'ParentID'
};
let ganttInstance;
const eventMarkerDay1 = new Date('04/02/2024');
const editSettings = {
allowAdding: true,
allowEditing: true,
allowDeleting: true,
allowTaskbarEditing: true,
showDeleteConfirmDialog: true,
};
const toolbar = ["Add", "Edit", "Update", "Delete", "Cancel", "ExpandAll", "CollapseAll"];
const timelineSettings = {
showTooltip: true,
topTier: {
unit: "Week",
format: "dd/MM/yyyy",
},
bottomTier: {
unit: "Day",
count: 1,
},
};
const labelSettings = {
taskLabel: '${Progress}%'
};
const projectStartDate = new Date("03/31/2024");
const projectEndDate = new Date("05/30/2024");
const splitterSettings = {
columnIndex: 4
};
const selectionSettings = {
mode: "Row",
type: "Single",
enableToggle: false,
};
const tooltipSettings = {
showTooltip: true,
};
const filterSettings = {
type: "Menu",
};
return <GanttComponent id="EnableWbs" taskFields={taskFields} ref={ganttInstance} toolbar={toolbar} treeColumnIndex={2} dataSource={WBSData} allowSorting={true} enableContextMenu={true} enableWBS={true} enableAutoWbsUpdate={true} editSettings={editSettings} allowSelection={true} allowPdfExport={true} splitterSettings={splitterSettings} selectionSettings={selectionSettings} tooltipSettings={tooltipSettings} filterSettings={filterSettings} timelineSettings={timelineSettings} highlightWeekends={true} allowFiltering={true} gridLines={"Both"} labelSettings={labelSettings} taskbarHeight={20} rowHeight={40} height={"550px"} allowUnscheduledTasks={true} projectStartDate={projectStartDate} projectEndDate={projectEndDate}>
<ColumnsDirective>
<ColumnDirective field="TaskID" visible={false} />
<ColumnDirective field="WBSCode" width='150px' />
<ColumnDirective field="TaskName" headerText="Task Name" allowReordering={false} width='260px' />
<ColumnDirective field="StartDate" headerText="Start Date" width='140px' />
<ColumnDirective field="WBSPredecessor" headerText="WBS Predecessor" width='190px' />
<ColumnDirective field="Duration" headerText="Duration" allowEditing={false} width='130px' />
<ColumnDirective field="Progress" headerText="Progress" />
</ColumnsDirective>
<EventMarkersDirective>
<EventMarkerDirective day={eventMarkerDay1} label='Project Initiation'></EventMarkerDirective>
</EventMarkersDirective>
<Inject services={[Selection, DayMarkers, Toolbar, Edit, Filter, Sort, ContextMenu]} />
</GanttComponent>
};
ReactDOM.render(<App />, document.getElementById('root'));<!DOCTYPE html>
<html lang="en">
<head>
<title>Syncfusion React Gantt</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Essential JS 2 for React Components" />
<meta name="author" content="Syncfusion" />
<link href="https://cdn.syncfusion.com/ej2/34.2.2/tailwind3.css" rel="stylesheet" type="text/css" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
<script src="systemjs.config.js"></script>
<style>
#loader {
color: #008cff;
height: 40px;
left: 45%;
position: absolute;
top: 45%;
width: 30%;
}
</style>
</head>
<body>
<div id='root'>
<div id='loader'>Loading....</div>
</div>
</body>
</html>Managing WBS code updates
To optimize performance, WBS code updates can be controlled using the actionBegin and dataBound events. This is especially useful during operations like row drag-and-drop, where auto-update is triggered only during that specific action to ensure efficient and accurate code handling.
In the following example, WBS auto-update is enabled only during the row drag and drop action using these events.
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
GanttComponent,
Inject,
Selection,
ColumnsDirective,
ColumnDirective,
Toolbar,
DayMarkers,
Edit,
Filter,
Sort,
ContextMenu,
EventMarkersDirective,
EventMarkerDirective,
RowDD
} from '@syncfusion/ej2-react-gantt';
import { WBSData } from './datasource';
function App() {
let ganttInstance;
let isRowDropped = false;
const taskFields = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
endDate: 'EndDate',
duration: 'Duration',
progress: 'Progress',
dependency: 'Predecessor',
parentID: 'ParentID'
};
const eventMarkerDay1 = new Date('04/02/2024');
const editSettings = {
allowAdding: true,
allowEditing: true,
allowDeleting: true,
allowTaskbarEditing: true,
showDeleteConfirmDialog: true
};
const toolbar = ['Add', 'Edit', 'Update', 'Delete', 'Cancel', 'ExpandAll', 'CollapseAll'];
const timelineSettings = {
showTooltip: true,
topTier: { unit: 'Week', format: 'dd/MM/yyyy' },
bottomTier: { unit: 'Day', count: 1 }
};
const labelSettings = { taskLabel: '${Progress}%' };
const projectStartDate = new Date('03/31/2024');
const projectEndDate = new Date('05/30/2024');
const splitterSettings = { columnIndex: 4 };
const selectionSettings = { mode: 'Row', type: 'Single', enableToggle: false };
const tooltipSettings = { showTooltip: true };
const filterSettings = { type: 'Menu' };
const dataBound = () => {
if (isRowDropped && ganttInstance) {
ganttInstance.enableAutoWbsUpdate = false;
isRowDropped = false;
}
};
const actionBegin = (args) => {
if (args.requestType === 'beforeDrop' && ganttInstance) {
isRowDropped = true;
ganttInstance.enableAutoWbsUpdate = true;
}
};
return (
<GanttComponent
id="EnableWbs"
ref={(gantt) => (ganttInstance = gantt)}
taskFields={taskFields}
toolbar={toolbar}
treeColumnIndex={2}
dataSource={WBSData}
allowSorting={true}
enableContextMenu={true}
enableWBS={true}
enableAutoWbsUpdate={true}
editSettings={editSettings}
allowSelection={true}
allowPdfExport={true}
splitterSettings={splitterSettings}
selectionSettings={selectionSettings}
tooltipSettings={tooltipSettings}
filterSettings={filterSettings}
timelineSettings={timelineSettings}
highlightWeekends={true}
allowFiltering={true}
gridLines="Both"
labelSettings={labelSettings}
taskbarHeight={20}
rowHeight={40}
height="550px"
allowUnscheduledTasks={true}
projectStartDate={projectStartDate}
projectEndDate={projectEndDate}
allowRowDragAndDrop={true}
dataBound={dataBound}
actionBegin={actionBegin}
>
<ColumnsDirective>
<ColumnDirective field="TaskID" visible={false} />
<ColumnDirective field="WBSCode" width="150px" />
<ColumnDirective field="TaskName" headerText="Task Name" allowReordering={false} width="260px" />
<ColumnDirective field="StartDate" headerText="Start Date" width="140px" />
<ColumnDirective field="WBSPredecessor" headerText="WBS Predecessor" width="190px" />
<ColumnDirective field="Duration" headerText="Duration" allowEditing={false} width="130px" />
<ColumnDirective field="Progress" headerText="Progress" />
</ColumnsDirective>
<EventMarkersDirective>
<EventMarkerDirective day={eventMarkerDay1} label="Project Initiation" />
</EventMarkersDirective>
<Inject services={[Selection, DayMarkers, Toolbar, Edit, Filter, Sort, ContextMenu, RowDD]} />
</GanttComponent>
);
}
ReactDOM.render(<App />, document.getElementById('root'));import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
GanttComponent,
Inject,
Selection,
ColumnsDirective,
ColumnDirective,
Toolbar,
DayMarkers,
Edit,
Filter,
Sort,
ContextMenu,
EventMarkersDirective,
EventMarkerDirective,
actionBeginEventArgs,
RowDD
} from '@syncfusion/ej2-react-gantt';
import { WBSData } from './datasource';
function App() {
let ganttInstance: GanttComponent;
let isRowDropped = false;
const taskFields = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
endDate: 'EndDate',
duration: 'Duration',
progress: 'Progress',
dependency: 'Predecessor',
parentID: 'ParentID'
};
const eventMarkerDay1 = new Date('04/02/2024');
const editSettings = {
allowAdding: true,
allowEditing: true,
allowDeleting: true,
allowTaskbarEditing: true,
showDeleteConfirmDialog: true
};
const toolbar = ['Add', 'Edit', 'Update', 'Delete', 'Cancel', 'ExpandAll', 'CollapseAll'];
const timelineSettings = {
showTooltip: true,
topTier: { unit: 'Week', format: 'dd/MM/yyyy' },
bottomTier: { unit: 'Day', count: 1 }
};
const labelSettings = { taskLabel: '${Progress}%' };
const projectStartDate = new Date('03/31/2024');
const projectEndDate = new Date('05/30/2024');
const splitterSettings = { columnIndex: 4 };
const selectionSettings = { mode: 'Row', type: 'Single', enableToggle: false };
const tooltipSettings = { showTooltip: true };
const filterSettings = { type: 'Menu' };
const dataBound = () => {
if (isRowDropped && ganttInstance) {
ganttInstance.enableAutoWbsUpdate = false;
isRowDropped = false;
}
};
const actionBegin = (args: actionBeginEventArgs) => {
if (args.requestType === 'beforeDrop' && ganttInstance) {
isRowDropped = true;
ganttInstance.enableAutoWbsUpdate = true;
}
};
return (
<GanttComponent
id="EnableWbs"
ref={(gantt) => (ganttInstance = gantt)}
taskFields={taskFields}
toolbar={toolbar}
treeColumnIndex={2}
dataSource={WBSData}
allowSorting={true}
enableContextMenu={true}
enableWBS={true}
enableAutoWbsUpdate={true}
editSettings={editSettings}
allowSelection={true}
allowPdfExport={true}
splitterSettings={splitterSettings}
selectionSettings={selectionSettings}
tooltipSettings={tooltipSettings}
filterSettings={filterSettings}
timelineSettings={timelineSettings}
highlightWeekends={true}
allowFiltering={true}
gridLines="Both"
labelSettings={labelSettings}
taskbarHeight={20}
rowHeight={40}
height="550px"
allowUnscheduledTasks={true}
projectStartDate={projectStartDate}
projectEndDate={projectEndDate}
allowRowDragAndDrop={true}
dataBound={dataBound}
actionBegin={actionBegin}
>
<ColumnsDirective>
<ColumnDirective field="TaskID" visible={false} />
<ColumnDirective field="WBSCode" width="150px" />
<ColumnDirective field="TaskName" headerText="Task Name" allowReordering={false} width="260px" />
<ColumnDirective field="StartDate" headerText="Start Date" width="140px" />
<ColumnDirective field="WBSPredecessor" headerText="WBS Predecessor" width="190px" />
<ColumnDirective field="Duration" headerText="Duration" allowEditing={false} width="130px" />
<ColumnDirective field="Progress" headerText="Progress" />
</ColumnsDirective>
<EventMarkersDirective>
<EventMarkerDirective day={eventMarkerDay1} label="Project Initiation" />
</EventMarkersDirective>
<Inject services={[Selection, DayMarkers, Toolbar, Edit, Filter, Sort, ContextMenu, RowDD]} />
</GanttComponent>
);
}
ReactDOM.render(<App />, document.getElementById('root'));<!DOCTYPE html>
<html lang="en">
<head>
<title>Syncfusion React Gantt</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Essential JS 2 for React Components" />
<meta name="author" content="Syncfusion" />
<link href="https://cdn.syncfusion.com/ej2/34.2.2/tailwind3.css" rel="stylesheet" type="text/css" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
<script src="systemjs.config.js"></script>
<style>
#loader {
color: #008cff;
height: 40px;
left: 45%;
position: absolute;
top: 45%;
width: 30%;
}
</style>
</head>
<body>
<div id='root'>
<div id='loader'>Loading....</div>
</div>
</body>
</html>Limitations
The WBS feature has a few limitations in the Gantt Chart component:
- Editing of the WBS code and WBS predecessor columns is not supported.
- Load on demand is not supported with the WBS feature.
- WBS Code and WBS Predecessor fields cannot be mapped directly from the data source.