Work Breakdown Structure (WBS) in Vue Gantt Component
28 Jun 202522 minutes to read
The Work Breakdown Structure (WBS) organizes project tasks hierarchically in the Gantt component by assigning unique codes to each task. This system enhances visualization and management by clearly reflecting task relationships and levels. It is especially useful in complex environments like construction projects or enterprise-scale software development.
Configuration and implementation
To enable and configure WBS in your Gantt component:
-
Enable WBS Codes: Set the
enableWBSproperty totrueto automatically generate unique task codes and their predecessors. -
Auto-Update Codes: Set the
enableAutoWbsUpdateproperty totrueto maintain WBS code accuracy during operations like sorting, filtering, editing, or drag-and-drop.
<template>
<div class="content-wrapper">
<ejs-gantt
ref="gantt"
id="HierarchyProjectview"
:dataSource="projectData"
:taskFields="taskFields"
:columns="columns"
:editSettings="editSettings"
:toolbar="toolbar"
:allowSorting="true"
:enableContextMenu="true"
:enableWBS="enableWBS"
:treeColumnIndex="2"
:enableAutoWbsUpdate="enableAutoWbsUpdate"
:allowFiltering="true"
:filterSettings="filterSettings"
:selectionSettings="selectionSettings"
:splitterSettings="splitterSettings"
:gridLines="'Both'"
:highlightWeekends="true"
:timelineSettings="timelineSettings"
:labelSettings="labelSettings"
:taskbarHeight="20"
:rowHeight="40"
:eventMarkers="eventMarkers"
:height="'550px'"
:allowUnscheduledTasks="true"
:projectStartDate="projectStartDate"
:projectEndDate="projectEndDate"
/>
</div>
</template>
<script setup>
import { provide, ref } from 'vue';
import { GanttComponent as EjsGantt, Selection, Toolbar, DayMarkers, Edit, Filter, Sort, ContextMenu } from '@syncfusion/ej2-vue-gantt';
import { WBSData } from './data-source';
const gantt = ref(null);
provide('gantt', [Selection, Toolbar, DayMarkers, Edit, Filter, Sort, ContextMenu]);
const enableWBS = true;
const enableAutoWbsUpdate = true;
const projectData = WBSData;
const projectStartDate = new Date('03/31/2024');
const projectEndDate = new Date('05/30/2024');
const taskFields = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
duration: 'Duration',
progress: 'Progress',
dependency: 'Predecessor',
parentID: 'ParentId',
};
const columns = [
{ field: 'TaskID', headerText: 'Task ID', visible: false },
{ field: 'WBSCode', headerText: 'WBS Code', width: '150px' },
{ field: 'TaskName', headerText: 'Task Name', allowReordering: false, width: '260px' },
{ field: 'StartDate', headerText: 'Start Date', width: '140px' },
{ field: 'WBSPredecessor', headerText: 'WBS Predecessor', width: '190px' },
{ field: 'Duration', headerText: 'Duration', allowEditing: false, width: '130px' },
{ field: 'Progress', headerText: 'Progress' },
];
const toolbar = ['Add', 'Edit', 'Update', 'Delete', 'Cancel', 'ExpandAll', 'CollapseAll'];
const filterSettings = { type: 'Menu' };
const selectionSettings = { mode: 'Row', type: 'Single', enableToggle: false };
const splitterSettings = { columnIndex: 4 };
const timelineSettings = {
showTooltip: true,
topTier: { unit: 'Week', format: 'dd/MM/yyyy' },
bottomTier: { unit: 'Day', count: 1 },
};
const labelSettings = {
leftLabel: 'TaskID',
rightLabel: 'Task Name: ${taskData.TaskName}',
taskLabel: '${Progress}%',
};
const eventMarkers = [{ day: new Date('04/02/2024'), label: 'Project Initiation' }];
</script><template>
<div class="content-wrapper">
<ejs-gantt
id="HierarchyProjectview"
:dataSource="projectData"
:taskFields="taskFields"
:columns="columns"
:editSettings="editSettings"
:toolbar="toolbar"
:allowSorting="true"
:enableContextMenu="true"
:enableWBS="enableWBS"
:treeColumnIndex="2"
:enableAutoWbsUpdate="enableAutoWbsUpdate"
:allowFiltering="true"
:filterSettings="filterSettings"
:selectionSettings="selectionSettings"
:splitterSettings="splitterSettings"
:gridLines="'Both'"
:highlightWeekends="true"
:timelineSettings="timelineSettings"
:labelSettings="labelSettings"
:taskbarHeight="20"
:rowHeight="40"
:eventMarkers="eventMarkers"
:height="'550px'"
:allowUnscheduledTasks="true"
:projectStartDate="projectStartDate"
:projectEndDate="projectEndDate"
/>
</div>
</template>
<script>
import { GanttComponent, Selection, Toolbar, DayMarkers, Edit, Filter, Sort, ContextMenu } from '@syncfusion/ej2-vue-gantt';
import { WBSData } from './data-source';
export default {
name: 'App',
components: {
'ejs-gantt': GanttComponent,
},
data() {
return {
enableWBS: true,
enableAutoWbsUpdate: true,
projectData: WBSData,
projectStartDate: new Date('03/31/2024'),
projectEndDate: new Date('05/30/2024'),
taskFields: {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
duration: 'Duration',
progress: 'Progress',
dependency: 'Predecessor',
parentID: 'ParentId',
},
columns: [
{ field: 'TaskID', headerText: 'Task ID', visible: false },
{ field: 'WBSCode', headerText: 'WBS Code', width: '150px' },
{ field: 'TaskName', headerText: 'Task Name', allowReordering: false, width: '260px' },
{ field: 'StartDate', headerText: 'Start Date', width: '140px' },
{ field: 'WBSPredecessor', headerText: 'WBS Predecessor', width: '190px' },
{ field: 'Duration', headerText: 'Duration', allowEditing: false, width: '130px' },
{ field: 'Progress', headerText: 'Progress' },
],
toolbar: ['Add', 'Edit', 'Update', 'Delete', 'Cancel', 'ExpandAll', 'CollapseAll'],
filterSettings: { type: 'Menu' },
selectionSettings: { mode: 'Row', type: 'Single', enableToggle: false },
splitterSettings: { columnIndex: 4 },
timelineSettings: {
showTooltip: true,
topTier: { unit: 'Week', format: 'dd/MM/yyyy' },
bottomTier: { unit: 'Day', count: 1 },
},
labelSettings: {
leftLabel: 'TaskID',
rightLabel: 'Task Name: ${taskData.TaskName}',
taskLabel: '${Progress}%',
},
eventMarkers: [{ day: new Date('04/02/2024'), label: 'Project Initiation' }],
};
},
provide: {
gantt: [Selection, Toolbar, DayMarkers, Edit, Filter, Sort, ContextMenu],
},
};
</script>Managing WBS code updates
For better performance, you can control when WBS codes are updated by using the actionBegin and dataBound events. This is particularly useful during actions like dragging and dropping rows.
In the following example, WBS auto-update is enabled only during the row drag and drop action using these events.
<template>
<div class="content-wrapper">
<ejs-gantt
ref="gantt"
id="HierarchyProjectview"
:dataSource="projectData"
:taskFields="taskFields"
:columns="columns"
:editSettings="editSettings"
:toolbar="toolbar"
:allowSorting="true"
:enableContextMenu="true"
:enableWBS="true"
:treeColumnIndex="2"
:enableAutoWbsUpdate="enableAutoWbsUpdate"
:allowFiltering="true"
:filterSettings="filterSettings"
:selectionSettings="selectionSettings"
:splitterSettings="splitterSettings"
:gridLines="'Both'"
:highlightWeekends="true"
:timelineSettings="timelineSettings"
:labelSettings="labelSettings"
:taskbarHeight="20"
:rowHeight="40"
:eventMarkers="eventMarkers"
:height="'550px'"
:allowUnscheduledTasks="true"
:projectStartDate="projectStartDate"
:projectEndDate="projectEndDate"
@actionBegin="actionBegin"
@dataBound="dataBound"
/>
</div>
</template>
<script setup>
import { ref, provide } from 'vue';
import {
GanttComponent as EjsGantt,
Selection,
Toolbar,
DayMarkers,
Edit,
Filter,
Sort,
ContextMenu
} from '@syncfusion/ej2-vue-gantt';
import { WBSData } from './data-source';
provide('gantt', [Selection, Toolbar, DayMarkers, Edit, Filter, Sort, ContextMenu]);
const gantt = ref(null);
const isRowDropped = ref(false);
const enableAutoWbsUpdate = ref(false);
const projectData = WBSData;
const taskFields = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
duration: 'Duration',
progress: 'Progress',
dependency: 'Predecessor',
parentID: 'ParentId',
};
const columns = [
{ field: 'TaskID', visible: false },
{ field: 'WBSCode', headerText: 'WBS Code', width: '150px' },
{ field: 'TaskName', headerText: 'Task Name', width: '260px' },
{ field: 'StartDate', headerText: 'Start Date', width: '140px' },
{ field: 'WBSPredecessor', headerText: 'WBS Predecessor', width: '190px' },
{ field: 'Duration', headerText: 'Duration', allowEditing: false, width: '130px' },
{ field: 'Progress', headerText: 'Progress' }
];
const editSettings = {
allowAdding: true,
allowEditing: true,
allowDeleting: true,
allowTaskbarEditing: true,
showDeleteConfirmDialog: true
};
const toolbar = ['Add', 'Edit', 'Update', 'Delete', 'Cancel', 'ExpandAll', 'CollapseAll'];
const filterSettings = { type: 'Menu' };
const selectionSettings = { mode: 'Row', type: 'Single' };
const splitterSettings = { columnIndex: 4 };
const timelineSettings = {
topTier: { unit: 'Week', format: 'dd/MM/yyyy' },
bottomTier: { unit: 'Day', count: 1 },
showTooltip: true
};
const labelSettings = {
leftLabel: 'TaskID',
rightLabel: 'Task Name: ${taskData.TaskName}',
taskLabel: '${Progress}%'
};
const eventMarkers = [{ day: new Date('04/02/2024'), label: 'Project Initiation' }];
const projectStartDate = new Date('03/31/2024');
const projectEndDate = new Date('05/30/2024');
function actionBegin(args) {
if (args.requestType === 'beforeDrop') {
isRowDropped.value = true;
gantt.value.ej2Instances.enableAutoWbsUpdate = true;
}
}
function dataBound() {
if (isRowDropped.value) {
gantt.value.ej2Instances.enableAutoWbsUpdate = false;
isRowDropped.value = false;
}
}
</script><template>
<div class="content-wrapper">
<ejs-gantt
ref="gantt"
id="HierarchyProjectview"
:dataSource="projectData"
:taskFields="taskFields"
:columns="columns"
:editSettings="editSettings"
:toolbar="toolbar"
:allowSorting="true"
:enableContextMenu="true"
:enableWBS="true"
:treeColumnIndex="2"
:enableAutoWbsUpdate="enableAutoWbsUpdate"
:allowFiltering="true"
:filterSettings="filterSettings"
:selectionSettings="selectionSettings"
:splitterSettings="splitterSettings"
:gridLines="'Both'"
:highlightWeekends="true"
:timelineSettings="timelineSettings"
:labelSettings="labelSettings"
:taskbarHeight="20"
:rowHeight="40"
:eventMarkers="eventMarkers"
:height="'550px'"
:allowUnscheduledTasks="true"
:projectStartDate="projectStartDate"
:projectEndDate="projectEndDate"
@actionBegin="actionBegin"
@dataBound="dataBound"
/>
</div>
</template>
<script>
import {
GanttComponent,
Selection,
Toolbar,
DayMarkers,
Edit,
Filter,
Sort,
ContextMenu
} from '@syncfusion/ej2-vue-gantt';
import { WBSData } from './data-source';
export default {
components: {
'ejs-gantt': GanttComponent
},
data() {
return {
isRowDropped: false,
enableAutoWbsUpdate: false,
projectData: WBSData,
taskFields: {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
duration: 'Duration',
progress: 'Progress',
dependency: 'Predecessor',
parentID: 'ParentId'
},
columns: [
{ field: 'TaskID', visible: false },
{ field: 'WBSCode', headerText: 'WBS Code', width: '150px' },
{ field: 'TaskName', headerText: 'Task Name', width: '260px' },
{ field: 'StartDate', headerText: 'Start Date', width: '140px' },
{ field: 'WBSPredecessor', headerText: 'WBS Predecessor', width: '190px' },
{ field: 'Duration', headerText: 'Duration', allowEditing: false, width: '130px' },
{ field: 'Progress', headerText: 'Progress' }
],
editSettings: {
allowAdding: true,
allowEditing: true,
allowDeleting: true,
allowTaskbarEditing: true,
showDeleteConfirmDialog: true
},
toolbar: ['Add', 'Edit', 'Update', 'Delete', 'Cancel', 'ExpandAll', 'CollapseAll'],
filterSettings: { type: 'Menu' },
selectionSettings: { mode: 'Row', type: 'Single' },
splitterSettings: { columnIndex: 4 },
timelineSettings: {
topTier: { unit: 'Week', format: 'dd/MM/yyyy' },
bottomTier: { unit: 'Day', count: 1 },
showTooltip: true
},
labelSettings: {
leftLabel: 'TaskID',
rightLabel: 'Task Name: ${taskData.TaskName}',
taskLabel: '${Progress}%'
},
eventMarkers: [{ day: new Date('04/02/2024'), label: 'Project Initiation' }],
projectStartDate: new Date('03/31/2024'),
projectEndDate: new Date('05/30/2024')
};
},
provide: {
gantt: [Selection, Toolbar, DayMarkers, Edit, Filter, Sort, ContextMenu]
},
methods: {
actionBegin(args) {
if (args.requestType === 'beforeDrop') {
this.isRowDropped = true;
this.$refs.gantt.ej2Instances.enableAutoWbsUpdate = true;
}
},
dataBound() {
if (this.isRowDropped) {
this.$refs.gantt.ej2Instances.enableAutoWbsUpdate = false;
this.isRowDropped = false;
}
}
}
};
</script>Limitations
The WBS feature has a few limitations in the Vue Gantt 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.