How to correctly implement a Hierarchical Numbering Column in Gantt Chart?

Gantt Chart by default has a column `ID` displaying tasks' primary key. But what I need is a column like this:

000screenshot.png

My current implementation and Question are: 

  1. Current Implementation: Database-side hierarchy numbering
    • Added two PostgreSQL triggers (compute_hierarchy and renumber_siblings) so that any insert/delete/update will recalc HierarchyNumber on the fly.
    • All backend endpoints reload the entity after save, so your triggers always fill in the latest numbers before you return data.

  2. Question: The UI gap
    • When you delete a task, the DB trigger correctly renumbers its siblings and your batch endpoint returns those updated siblings in changedRecords.
     Problem: Syncfusion Gantt isn’t automatically rebinding those sibling rows, so the grid keeps showing the old numbers.

  3. Two paths forward

    1. Manual refresh
      • In actionComplete (or use a component ref), call .refresh() (or loop updateRecordByID) to force the grid to redraw.
      • ✅ This works, but it bypasses the built-in DataManager mechanism.
    2. Batch-mode via DataManager
      • Leverage UrlAdaptor’s support for { action: 'batch', addedRecords, changedRecords, deletedRecords }.
      • The Gantt in Batch edit mode should consume those arrays and update exactly the affected rows without a full refresh.
       Current hitch: We’ve set batchUrl, editSettings.mode='Batch', and returned the correct arrays, but the grid still fires single-record saves or doesn’t trigger its internal batchSave path.
  4. Why this is tricky
    • Syncfusion’s docs show how to toggle “Cell” vs. “Batch” edit, but they don’t explicitly spell out the URL-shape or event sequence.
    • In practice, Gantt will only apply your changedRecords when its own requestType is exactly batchSave. Anything else (single-save, refresh, etc.) drops that array.


please help, thanks


code is here:

<script setup>
import { GanttComponent as EjsGantt, ContextMenu, Edit, Selection, Toolbar, Resize, Sort, ExcelExport, PdfExport } from '@syncfusion/ej2-vue-gantt';
import { provide, ref } from 'vue';
import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';

// Configure DataManager for remote CRUD
const baseUrl = 'http://localhost:3000/api/tasks';
const dataManager = new DataManager({
  url: baseUrl,
  batchUrl: baseUrl,
  adaptor: new UrlAdaptor(),
  crossDomain: true,
  idMapping: 'TaskID'
});

// Define task fields mapping
const taskFields = {
  id: 'TaskID',
  name: 'TaskName',
  startDate: 'StartDate',
  endDate: 'EndDate',
  duration: 'Duration',
  progress: 'Progress',
  parentID: 'parentId'
};

// Define edit settings for Gantt
const editSettings = {
  allowAdding: true,
  allowEditing: true,
  allowDeleting: true,
  allowTaskbarEditing: true,
  showDeleteConfirmDialog: true,
  addRowPosition: 'Child',
  allowBatchSave: true  // enable batch CRUD mode
};

// Define toolbar items for Gantt actions
const toolbar = [
  'Add', 'Edit', 'Delete', 'Update', 'Cancel',
  'ExpandAll', 'CollapseAll', 'ExcelExport', 'PdfExport'
];
// Reference to Gantt component for invoking batch save
const ganttRef = ref(null);
// Intercept single-record saves/deletes and rerun as batchSave
function onActionBegin(args) {
  console.log('[Gantt Debug] actionBegin', args.requestType, args.data);
  // Intercept single-record add or delete to trigger batchSave
  if ((args.requestType === 'beforeAdd' || args.requestType === 'beforeDelete')) {
    console.log('[Gantt Debug] intercepting single operation, cancelling and triggering batchSave');
    args.cancel = true;
    // use batch save to consume changedRecords from server
    ganttRef.value.ej2Instances.saveChanges();
  }
}

// Log completion of batchSave or other actions
function onActionComplete(args) {
  console.log('[Gantt Debug] actionComplete', args.requestType, args.data, args);  
}

// Define grid columns, replacing default ID with HierarchyNumber
const columns = [
  // Hidden primary key column for TreeGrid
  { field: 'TaskID', headerText: 'TaskID', isPrimaryKey: true, visible: false, allowResizing: true },
  // Visible hierarchical number with tooltip on overflow
  { field: 'HierarchyNumber', headerText: 'ID', width: 100, textAlign: 'Left', allowResizing: true, clipMode: 'EllipsisWithTooltip' },
  { field: 'TaskName', headerText: 'Name', width: 250, textAlign: 'Left', allowResizing: true },
  { field: 'StartDate', headerText: 'Start Date', width: 120, format: 'MM/dd/yyyy', textAlign: 'Left', allowResizing: true },
  { field: 'EndDate', headerText: 'End Date', width: 120, format: 'MM/dd/yyyy', textAlign: 'Left', allowResizing: true },
  { field: 'Progress', headerText: 'Progress', width: 100, textAlign: 'Right', allowResizing: true }
];

// Provide required Gantt and TreeGrid modules (including batch editing)
provide('gantt', [ContextMenu, Edit, Selection, Toolbar, Resize, Sort, ExcelExport, PdfExport]);
</script>

<template>
  <ejs-gantt
    ref="ganttRef"
    @actionBegin="onActionBegin"
    @actionComplete="onActionComplete"
    :dataSource="dataManager"
    :taskFields="taskFields"
    :editSettings="editSettings"
    :toolbar="toolbar"
    :enableContextMenu="true"
    :columns="columns"
    :allowResizing="true"
    :allowSelection="true"
    :allowExcelExport="true"
    :allowPdfExport="true"
    :allowSorting="true"
    height="450px"
    :treeColumnIndex="1"
  />
</template>

<style>
/* Material theme used for this sample */
 @import "@syncfusion/ej2-base/styles/material.css";
 @import "@syncfusion/ej2-buttons/styles/material.css";
 @import "@syncfusion/ej2-calendars/styles/material.css";
 @import "@syncfusion/ej2-dropdowns/styles/material.css";
 @import "@syncfusion/ej2-inputs/styles/material.css";
 @import "@syncfusion/ej2-navigations/styles/material.css";
 @import "@syncfusion/ej2-popups/styles/material.css";
 @import "@syncfusion/ej2-splitbuttons/styles/material.css";
 @import "@syncfusion/ej2-layouts/styles/material.css";
 @import "@syncfusion/ej2-grids/styles/material.css";
 @import "@syncfusion/ej2-treegrid/styles/material.css";
 @import "@syncfusion/ej2-vue-gantt/styles/material.css";
</style>


3 Replies 1 reply marked as answer

SJ Sridharan Jayabalan Syncfusion Team June 16, 2025 12:14 PM UTC

Hi Ryan,

 

Greetings from Syncfusion.

 

Thank you for your detailed explanation.

 

From your description, it seems that you are looking for functionality similar to Work Breakdown Structure (WBS) numbering. We're happy to inform you that WBS support is planned and will be included in our upcoming Volume 2 main release, scheduled for the end of June 2025.

 

With this feature, you can enable a built-in WBS column that auto-generates hierarchical numbering (e.g., 1, 1.1, 1.2, 2, 2.1, etc.) and updates automatically during operations like row drag-and-drop and CRUD actions. Please note that the WBS values are internally generated and cannot be manually mapped to a data source field.

 

Could you please confirm if this upcoming feature aligns with your requirement, or if you are looking for a different kind of functionality?

 

 

Regards,

Sridharan


Marked as answer

RY Ryan.L replied to Sridharan Jayabalan June 29, 2025 06:38 AM UTC

Thank you for the reply. It's exactly what  I was looking for, good work Syncfusion Team



AG Ajithkumar Gopalakrishnan Syncfusion Team June 30, 2025 09:28 AM UTC

Hi Ryan,

Thanks for your patience.

We are glad to announce that our Essential Studio 2025 Volume 2 main release v30.1.37 is rolled out and is available for download under the following link.

https://www.syncfusion.com/forums/197054/essential-studio-2025-volume-2-main-release-v30-1-37-is-available-for-download

Thank you for your support and appreciate your patience in waiting for this release. Please get in touch with us if you would require any further assistance.

The improvement feature “WBS support" has been rolled out in our Volume 2 Main Release v30.1.37. So upgrade to our latest version to resolve the problem.

Release Notes -  https://ej2.syncfusion.com/react/documentation/release-notes/30.1.37?type=all#ganttchart

To use WBS feature in your application:

  1. Enable WBS Support
    Set the enableWBS property to true to automatically generate WBS codes and WBS predecessors for all tasks.
  2. Auto-Update WBS Codes
    Set the enableAutoWbsUpdate property to true to ensure that WBS codes are recalculated automatically whenever the task hierarchy changes (e.g., tasks are moved or restructured).
  3. Display WBS Codes
    Use the WBSCode field in the column definitions to display the generated WBS codes in the Gantt chart grid.

const DragAndDrop = () => {

  return (

        <GanttComponent

          enableWBS={true}

          enableAutoWbsUpdate={true}

        >

          <ColumnsDirective>

            <ColumnDirective field="WBSCode" width="150px" />

          </ColumnsDirective>

          <Inject services={[Edit, RowDD, Selection]} />

        </GanttComponent>

  );

};

 

Sample - https://stackblitz.com/edit/react-g9qxufje-tkswbjx6?file=index.js

Demo - Gantt Chart · WBS Column · Syncfusion React UI Components

If you have any further questions or need additional assistance, please let me know!

Regards,
Ajithkumar G


Loader.
Up arrow icon