Odd Behavior with Gantt Chart Expansion and API Calls with (load on demand)

Hello Syncfusion team,

I've been working with the Syncfusion Gantt Chart and using a custom adaptor to handle data loading. I have a setup where:

  1. Initial Load: My backend returns only 5 tasks on the first level (the root tasks).
  2. Expansion: When I expand a task, the backend provides the children of that task. This hierarchy continues down, and the total number of records is 50,000.

Problem:

  • Currently, when I scroll or collapse tasks, an API call is made, which I don't want. I only want API calls to happen on task expansion.
  • After expanding a task, the new data replaces the existing data, instead of appending it correctly in the Gantt chart.
  • On the first call (which fetches only 5 records for the root tasks), the Gantt chart shows a long scroll bar, although there are only 5 records loaded initially.

What I Want to Achieve:

  • API Call: Only when expanding a task (no calls on scroll or collapse).
  • Data Merging: When I expand a task, I want the new data (children) to be added to the existing Gantt chart data without replacing it.
  • Scroll Behavior: I would like the scroll to reflect the correct number of records loaded, and adjust dynamically when new tasks are expanded and fetched from the server.

My Custom Adaptor:

```javascript

import { UrlAdaptor } from '@syncfusion/ej2-data';
import moment from 'moment';

export class CustomGanttAdaptor extends UrlAdaptor {

  // Overriding processQuery to modify API call
  processQuery(dm: any, query: any, hierarchyFilters: any) {

    const result: any = super.processQuery(dm, query, hierarchyFilters);

    // Construct the URL with query parameters
    const url = new URL(result.url, typeof location !== 'undefined' ? location.origin : '');
    result.type = 'GET';

    // Handle expanding a task
    if (query.expands && query.expands[0] == "ExpandingAction") {
      const expandingParentId = parseInt(query.expands[1]);
      url.searchParams.append('parentTaskId', expandingParentId.toString());
    }

    // Return the modified request
    return { ...result, url: url.toString() };

  }

  // Overriding processResponse to format data before sending it to the Gantt component
  processResponse(data: any, ds: any, query: any, xhr: any) {

    // Custom transformation of the received data
    const transformTasks = (task: any) => {
      const transformedTask: any = {
        level: task.level,
        key: task.taskId,
        TaskID: task.taskId,
        TaskName: task.taskName,
        Progress: task.progressPercent,
        StartDate: task.actualStart ? new Date(task.actualStart) : new Date(task.plannedStart),
        EndDate: task.actualStart == null ? moment(task.plannedFinish).toDate() : task.actualFinish == null ? moment(task.actualStart).add(task.actualDuration, 'days').toDate() : moment(task.actualFinish).toDate(),
        Duration: task.actualDuration == 0 ? task.plannedDuration : task.actualDuration,
        Predecessor: task.taskPredecessors,
        BaselineStartDate: new Date(task.plannedStart),
        BaselineEndDate: new Date(task.plannedFinish),
        reportsData: task.taskForms,
        parentID: task.parentTaskId,
        isParent: task.isParent
      };
      return transformedTask;
    };

    let transformedData = {
      result: data?.projectGantt?.projectTasksDto.map((task: any) => transformTasks(task)) || [],
      count: data?.projectGantt?.totalNumberOfTasks || 0
    };

    return (transformedData)

  }

}

```javascript

How I Use the Custom Adaptor in My Component:

```javascript

    useEffect(() => {
        if (projectId) {
            const dataManager = new DataManager({
                url: `${process.env.NEXT_PUBLIC_API_BASE_URL}api/Project/GetPaginatedProjectGantt?projectId=${projectId}`,
                adaptor: new CustomGanttAdaptor(),
                headers: [{ 'Authorization': `Bearer ${opteamToken}` }]
            });
            setDataManager(dataManager);
        }
    }, [projectId]);

```javascript

My Questions:

  1. Scroll Behavior: Is there a way to adjust the scroll bar to reflect only the tasks loaded (not showing a long scroll initially when only 5 tasks are loaded)?
  2. Appending Data: How can I append the newly expanded task’s data to the existing data, rather than replacing it entirely?
  3. Prevent API Calls: How can I prevent API calls on scroll and collapse, and only trigger them on task expansion?

Thank you in advance for your support!


11 Replies

SJ Sridharan Jayabalan Syncfusion Team October 17, 2024 01:44 PM UTC

Hi Loai,


Query 1 - Scroll Behavior: Is there a way to adjust the scroll bar to reflect only the tasks loaded (not showing a long scroll initially when only 5 tasks are loaded)?
You need to ensure that the count value reflects the exact number of records being loaded. If you send a count of 50,000 from the server while only loading 5 tasks, the Gantt chart will display a long scrollbar. Ensure the correct data and count values are returned from the server. Here's an example of what the server-side response should look like:

return dm.RequiresCounts ? Json(new { result = DataSource, count = count, flatData = data }) : Json(DataSource);



Query 2 - Appending Data: How can I append the newly expanded task’s data to the existing data, rather than replacing it entirely?

To achieve this, ensure that when a task is expanded, the child records are appended rather than replacing the entire dataset. You’ll need to modify your server-side logic to return both the parent and child records as required.
For example, in the sample below, when running, there are 18 parent records on the initial load. After expanding Parent 2, the child record count increases to 99, making the total record count 117. The code below checks for the expand/collapse action and skips the records after 13 records are displayed. Like this way, you can modify the server-side code as per your requirements. Please refer to the attached sample for reference.
HomeController.cs:-

if (dm.Expand != null && dm.Expand[0] == "CollapsingAction") // setting the skip index based on collapsed parent
       {
                string IdMapping = "taskId";
                List<WhereFilter> CollapseFilter = new List<WhereFilter>();
                CollapseFilter.Add(new WhereFilter() { Field = IdMapping, value = dm.Where[0].value, Operator = dm.Where[0].Operator });
                var CollapsedParentRecord = operation.PerformFiltering(DataSource, CollapseFilter, "and");
                var index = data.Cast<object>().ToList().IndexOf(CollapsedParentRecord.Cast<object>().ToList()[0]);
                dm.Skip = index;
            }

else if (dm.Expand != null && dm.Expand[0] == "ExpandingAction") // setting the skip index based on expanded parent
            {
                string IdMapping = "taskId";
                List<WhereFilter> ExpandFilter = new List<WhereFilter>();
                ExpandFilter.Add(new WhereFilter() { Field = IdMapping, value = dm.Where[0].value, Operator = dm.Where[0].Operator });
                var ExpandedParentRecord = operation.PerformFiltering(DataSource, ExpandFilter, "and");
                var index = data.Cast<object>().ToList().IndexOf(ExpandedParentRecord.Cast<object>().ToList()[0]);
                dm.Skip = index;
       }


Query 3 - Prevent API Calls: How can I prevent API calls on scroll and collapse, and only trigger them on task expansion?

Unfortunately, it’s not possible to fully prevent API calls on scrolling and collapsing due to the Gantt chart's default behavior of load-on-demand. This ensures that new data is fetched from the server during scrolling. However, you can handle task expansion and make API calls only during those events. You can customize the behavior as needed, but scrolling and collapse actions will still trigger API calls to load data.

For a working example, you can download the attached sample and view the demo here:

Sample - https://www.syncfusion.com/downloads/support/directtrac/general/ze/loadOnDemandMultiLevel_1-1566860281.zip

Demo - Gantt Chart · Big Data Set · Syncfusion React UI Components

Documentation - Data binding in React Gantt component | Syncfusion

                        Remote data in React Treegrid component | Syncfusion



Regards,

Sridharan



LZ Loai Zewail November 8, 2024 06:20 PM UTC

Hello Syncfusion Team,

Thank you for the quick response!

I’ve tried the suggestions you provided, and I’m encountering some new issues.

I’m facing issues with hierarchy, levels, and proper child assignment in the Gantt Chart component while using a custom data manager adaptor in my Next.js application.

I’m working with a hierarchical data structure where tasks can have multiple levels of nested children. 

Here’s a breakdown of the behavior I’m seeing:

Initial Load: After receiving the initial data from the backend, the Gantt chart displays correctly.
Initial Load Screenshot: Image 1 in .rar
Initial Backend Response: 

{
    "result": [
        {
            "taskId": 166395,
            "taskName": "SAFA TWO BASELINE PROGRAMME _Rev .0 ver.02 updates as of 13-Sep-24",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2028-07-17T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2028-07-17T18:00:00Z",
            "duration": "1548",
            "progress": 9,
            "parentID": null,
            "isExpanded": true,
            "isParent": true,
            "predecessor": null,
            "level": null
        },
        {
            "taskId": 166396,
            "taskName": "General",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2028-07-17T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2028-07-17T18:00:00Z",
            "duration": "1548",
            "progress": 9,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166397,
            "taskName": "Authority Approvals & NOC's",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2027-09-28T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2027-09-28T18:00:00Z",
            "duration": "1255",
            "progress": 11,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166398,
            "taskName": "Engineering",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2027-11-19T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2027-11-19T18:00:00Z",
            "duration": "1307",
            "progress": 11,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166399,
            "taskName": "Procurement",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2028-01-08T13:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2028-01-08T13:00:00Z",
            "duration": "1356",
            "progress": 10,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166400,
            "taskName": "Construction",
            "startDate": "2024-04-23T08:00:00Z",
            "endDate": "2028-05-10T18:00:00Z",
            "baselineStartDate": "2024-04-26T08:00:00Z",
            "baselineEndDate": "2028-05-10T18:00:00Z",
            "duration": "1479",
            "progress": 9,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166401,
            "taskName": "Final Works",
            "startDate": "2024-09-30T18:00:00Z",
            "endDate": "2028-07-17T18:00:00Z",
            "baselineStartDate": "2024-09-30T18:00:00Z",
            "baselineEndDate": "2028-07-17T18:00:00Z",
            "duration": "1386",
            "progress": 0,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        }
    ],
    "count": 7
}

First Expand Action: When expanding the task "General," it initially displays as expected.
First Expand Screenshot: Image 2  in .rar
Backend Response for First Expand: 

{

    "result": [
        {
            "taskId": 166396,
            "taskName": "General",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2028-07-17T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2028-07-17T18:00:00Z",
            "duration": "1548",
            "progress": 9,
            "parentID": 166395,
            "isExpanded": true,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166402,
            "taskName": "Project Milestone",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2028-07-17T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2028-07-17T18:00:00Z",
            "duration": "1548",
            "progress": 9,
            "parentID": 166396,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 2
        },
        {
            "taskId": 166403,
            "taskName": "Mobilization&Demoblization",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2028-04-12T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2028-04-12T18:00:00Z",
            "duration": "1206",
            "progress": 10,
            "parentID": 166396,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 2
        },
        {
            "taskId": 166397,
            "taskName": "Authority Approvals & NOC's",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2027-09-28T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2027-09-28T18:00:00Z",
            "duration": "1255",
            "progress": 11,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166398,
            "taskName": "Engineering",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2027-11-19T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2027-11-19T18:00:00Z",
            "duration": "1307",
            "progress": 11,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166399,
            "taskName": "Procurement",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2028-01-08T13:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2028-01-08T13:00:00Z",
            "duration": "1356",
            "progress": 10,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166400,
            "taskName": "Construction",
            "startDate": "2024-04-23T08:00:00Z",
            "endDate": "2028-05-10T18:00:00Z",
            "baselineStartDate": "2024-04-26T08:00:00Z",
            "baselineEndDate": "2028-05-10T18:00:00Z",
            "duration": "1479",
            "progress": 9,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166401,
            "taskName": "Final Works",
            "startDate": "2024-09-30T18:00:00Z",
            "endDate": "2028-07-17T18:00:00Z",
            "baselineStartDate": "2024-09-30T18:00:00Z",
            "baselineEndDate": "2028-07-17T18:00:00Z",
            "duration": "1386",
            "progress": 0,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        }
    ],
    "count": 9
}


Nested Expansion Issue: The issue occurs when I expand a nested child under "General." The hierarchy becomes misaligned, and the levels appear incorrectly.
Nested Expand Screenshot: Image 3  in .rar
Backend Response for Nested Expand: 

{

    "result": [
        {
            "taskId": 166402,
            "taskName": "Project Milestone",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2028-07-17T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2028-07-17T18:00:00Z",
            "duration": "1548",
            "progress": 9,
            "parentID": 166396,
            "isExpanded": true,
            "isParent": true,
            "predecessor": null,
            "level": 2
        },
        {
            "taskId": 166424,
            "taskName": "Contractual Milestones",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2028-07-17T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2028-07-17T18:00:00Z",
            "duration": "1548",
            "progress": 9,
            "parentID": 166402,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 3
        },
        {
            "taskId": 166397,
            "taskName": "Authority Approvals & NOC's",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2027-09-28T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2027-09-28T18:00:00Z",
            "duration": "1255",
            "progress": 11,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166398,
            "taskName": "Engineering",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2027-11-19T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2027-11-19T18:00:00Z",
            "duration": "1307",
            "progress": 11,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166399,
            "taskName": "Procurement",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2028-01-08T13:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2028-01-08T13:00:00Z",
            "duration": "1356",
            "progress": 10,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166400,
            "taskName": "Construction",
            "startDate": "2024-04-23T08:00:00Z",
            "endDate": "2028-05-10T18:00:00Z",
            "baselineStartDate": "2024-04-26T08:00:00Z",
            "baselineEndDate": "2028-05-10T18:00:00Z",
            "duration": "1479",
            "progress": 9,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166401,
            "taskName": "Final Works",
            "startDate": "2024-09-30T18:00:00Z",
            "endDate": "2028-07-17T18:00:00Z",
            "baselineStartDate": "2024-09-30T18:00:00Z",
            "baselineEndDate": "2028-07-17T18:00:00Z",
            "duration": "1386",
            "progress": 0,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166425,
            "taskName": "Control Milestones",
            "startDate": "2027-12-06T13:00:00Z",
            "endDate": "2028-07-17T18:00:00Z",
            "baselineStartDate": "2027-12-06T13:00:00Z",
            "baselineEndDate": "2028-07-17T18:00:00Z",
            "duration": "224",
            "progress": 0,
            "parentID": 166402,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 3
        },
        {
            "taskId": 166403,
            "taskName": "Mobilization&Demoblization",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2028-04-12T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2028-04-12T18:00:00Z",
            "duration": "1206",
            "progress": 10,
            "parentID": 166396,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 2
        }
    ],
    "count": 11
}


Page Refresh Issue: When I refresh the page, the tasks lose their indentation, and all items appear on the first level, with no child-parent relationships.
Page Refresh Screenshot: Image 4  in .rar
Backend Response on Refresh:

{


    "result": [
        {
            "taskId": 166395,
            "taskName": "SAFA TWO BASELINE PROGRAMME _Rev .0 ver.02 updates as of 13-Sep-24",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2028-07-17T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2028-07-17T18:00:00Z",
            "duration": "1548",
            "progress": 9,
            "parentID": null,
            "isExpanded": true,
            "isParent": true,
            "predecessor": null,
            "level": null
        },
        {
            "taskId": 166396,
            "taskName": "General",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2028-07-17T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2028-07-17T18:00:00Z",
            "duration": "1548",
            "progress": 9,
            "parentID": 166395,
            "isExpanded": true,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166402,
            "taskName": "Project Milestone",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2028-07-17T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2028-07-17T18:00:00Z",
            "duration": "1548",
            "progress": 9,
            "parentID": 166396,
            "isExpanded": true,
            "isParent": true,
            "predecessor": null,
            "level": 2
        },
        {
            "taskId": 166424,
            "taskName": "Contractual Milestones",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2028-07-17T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2028-07-17T18:00:00Z",
            "duration": "1548",
            "progress": 9,
            "parentID": 166402,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 3
        },
        {
            "taskId": 166397,
            "taskName": "Authority Approvals & NOC's",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2027-09-28T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2027-09-28T18:00:00Z",
            "duration": "1255",
            "progress": 11,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166398,
            "taskName": "Engineering",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2027-11-19T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2027-11-19T18:00:00Z",
            "duration": "1307",
            "progress": 11,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166399,
            "taskName": "Procurement",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2028-01-08T13:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2028-01-08T13:00:00Z",
            "duration": "1356",
            "progress": 10,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166400,
            "taskName": "Construction",
            "startDate": "2024-04-23T08:00:00Z",
            "endDate": "2028-05-10T18:00:00Z",
            "baselineStartDate": "2024-04-26T08:00:00Z",
            "baselineEndDate": "2028-05-10T18:00:00Z",
            "duration": "1479",
            "progress": 9,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166401,
            "taskName": "Final Works",
            "startDate": "2024-09-30T18:00:00Z",
            "endDate": "2028-07-17T18:00:00Z",
            "baselineStartDate": "2024-09-30T18:00:00Z",
            "baselineEndDate": "2028-07-17T18:00:00Z",
            "duration": "1386",
            "progress": 0,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        {
            "taskId": 166425,
            "taskName": "Control Milestones",
            "startDate": "2027-12-06T13:00:00Z",
            "endDate": "2028-07-17T18:00:00Z",
            "baselineStartDate": "2027-12-06T13:00:00Z",
            "baselineEndDate": "2028-07-17T18:00:00Z",
            "duration": "224",
            "progress": 0,
            "parentID": 166402,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 3
        },
        {
            "taskId": 166403,
            "taskName": "Mobilization&Demoblization",
            "startDate": "2024-04-22T08:00:00Z",
            "endDate": "2028-04-12T18:00:00Z",
            "baselineStartDate": "2024-04-22T08:00:00Z",
            "baselineEndDate": "2028-04-12T18:00:00Z",
            "duration": "1206",
            "progress": 10,
            "parentID": 166396,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 2
        }
    ],
    "count": 11
}


And the isuue keeps happening with expanding and collapsing childeren all tasks lose their  hierarchy.

I believe the issue might be related to incorrect level assignments and child-parent mapping upon data retrieval.

Here’s an example of the row data for a correct item after the first expand action:
Correct Row Data Example:

{
    "index": 2,
    "taskId": 166402,
    "taskName": "Project Milestone",
    "startDate": "2024-04-22T08:00:00.000Z",
    "endDate": "2028-07-17T18:00:00.000Z",
    "baselineStartDate": "2024-04-22T08:00:00.000Z",
    "baselineEndDate": "2028-07-17T18:00:00.000Z",
    "duration": "1548",
    "progress": 9,
    "parentID": 166396,
    "isExpanded": false,
    "isParent": true,
    "predecessor": null,
    "level": 2,
    "taskData": {
        "taskId": 166402,
        "taskName": "Project Milestone",
        "startDate": "2024-04-22T08:00:00.000Z",
        "endDate": "2028-07-17T18:00:00.000Z",
        "baselineStartDate": "2024-04-22T08:00:00.000Z",
        "baselineEndDate": "2028-07-17T14:00:00.000Z",
        "duration": 1548,
        "progress": 9,
        "parentID": 166396,
        "isExpanded": false,
        "isParent": true,
        "predecessor": null,
        "level": 2
    },
    "parentItem": {
        "taskId": 166396,
        "taskName": "General",
        "startDate": "2024-04-22T08:00:00.000Z",
        "endDate": "2028-07-17T18:00:00.000Z",
        "baselineStartDate": "2024-04-22T08:00:00.000Z",
        "baselineEndDate": "2028-07-17T18:00:00.000Z",
        "duration": "1548",
        "progress": 9,
        "parentID": 166395,
        "isExpanded": false,
        "isParent": true,
        "predecessor": null,
        "level": 1,
        "taskData": {
            "taskId": 166396,
            "taskName": "General",
            "startDate": "2024-04-22T08:00:00.000Z",
            "endDate": "2028-07-17T18:00:00.000Z",
            "baselineStartDate": "2024-04-22T08:00:00.000Z",
            "baselineEndDate": "2028-07-17T18:00:00.000Z",
            "duration": "1548",
            "progress": 9,
            "parentID": 166395,
            "isExpanded": false,
            "isParent": true,
            "predecessor": null,
            "level": 1
        },
        "uniqueID": "treeGridgantt_292070222_0_data_9",
        "index": 334,
        "hasChildRecords": true,
        "checkboxState": "uncheck",
        "parentItem": null,
        "expanded": true
    },
    "parentUniqueID": "treeGridgantt_292070222_0_data_9",
    "uniqueID": "treeGridgantt_292070222_0_data_23",
    "checkboxState": "uncheck",
    "hasChildRecords": true,
    "expanded": false,
    "column": {
        "disableHtmlEncode": true,
        "allowSorting": true,
        "allowResizing": true,
        "allowFiltering": true,
        "allowGrouping": true,
        "allowReordering": true,
        "showColumnMenu": true,
        "enableGroupByFormat": false,
        "allowEditing": true,
        "showInColumnChooser": true,
        "allowSearching": true,
        "autoFit": false,
        "sortDirection": "Descending",
        "field": "taskName",
        "width": "300",
        "textAlign": "Left",
        "editType": "stringedit",
        "type": "string",
        "uid": "grid-column2",
        "foreignKeyField": "taskName",
        "visible": true,
        "index": 2
    }
}

And here’s an example of an incorrect row data response in the wrong scenarios for the same task:
Incorrect Row Data Example: 

{
    "index": 553,
    "taskId": 166402,
    "taskName": "Project Milestone",
    "startDate": "2024-04-22T08:00:00.000Z",
    "endDate": "2028-07-17T18:00:00.000Z",
    "baselineStartDate": "2024-04-22T08:00:00.000Z",
    "baselineEndDate": "2028-07-17T18:00:00.000Z",
    "duration": "1548",
    "progress": 9,
    "parentID": 166396,
    "isExpanded": false,
    "isParent": true,
    "predecessor": null,
    "level": 1,
    "taskData": {
        "taskId": 166402,
        "taskName": "Project Milestone",
        "startDate": "2024-04-22T08:00:00.000Z",
        "endDate": "2028-07-17T18:00:00.000Z",
        "baselineStartDate": "2024-04-22T08:00:00.000Z",
        "baselineEndDate": "2028-07-17T18:00:00.000Z",
        "duration": "1548",
        "progress": 9,
        "parentID": 166396,
        "isExpanded": false,
        "isParent": true,
        "predecessor": null,
        "level": 2
    },
    "uniqueID": "treeGridgantt_292070222_0_data_10",
    "hasChildRecords": true,
    "checkboxState": "uncheck",
    "column": {
        "disableHtmlEncode": true,
        "allowSorting": true,
        "allowResizing": true,
        "allowFiltering": true,
        "allowGrouping": true,
        "allowReordering": true,
        "showColumnMenu": true,
        "enableGroupByFormat": false,
        "allowEditing": true,
        "showInColumnChooser": true,
        "allowSearching": true,
        "autoFit": false,
        "sortDirection": "Descending",
        "field": "taskName",
        "width": "300",
        "textAlign": "Left",
        "editType": "stringedit",
        "type": "string",
        "uid": "grid-column2",
        "foreignKeyField": "taskName",
        "visible": true,
        "index": 2
    }
}


Could you please advise on how to resolve this hierarchy and level assignment issue to ensure tasks are indented correctly and children are assigned to the correct parents on every expand action and to make everything correct also with scrolling and all actions ?

Thank you in advance for your help!


Attachment: screenshots_17c9e3c2.rar


LZ Loai Zewail November 8, 2024 06:52 PM UTC

I wanted to add also that I'm using the correct task settings for mapping :

let taskSettings = {
        id: 'taskId',
        name: 'taskName',
        progress: 'progress',
        startDate: 'startDate',
        endDate: 'endDate',
        duration: 'duration',
        baselineStartDate: 'baselineStartDate',
        baselineEndDate: 'baselineEndDate',
        hasChildMapping: 'isParent',
        parentID: 'parentID',
        expandStateMapping: 'isExpanded'
    };



UA Udhayakumar Anand Syncfusion Team November 11, 2024 01:18 PM UTC

Loai

We have reviewed your query, and from the information provided, it appears that the returned data is being sent incorrectly. We render the returned data in the Gantt chart in the order it is received, and an incorrect order is leading to the error you mentioned. To investigate further, please provide us with the following information for validation.

  1. Code snippet of the server-side logic used to return data when the expand action is triggered.
  2. Provide details of the data source being used.
  3. If virtual scrolling is implemented, ensure that the data returned aligns with the viewport requirements.
  4. Please share a server-side code sample or modify the provided sample, which will assist us in further validation.

Client side NextJs - https://www.syncfusion.com/downloads/support/directtrac/general/ze/REACTN~1-450339436


Server side -https://www.syncfusion.com/downloads/support/directtrac/general/ze/loadOnDemandMultiLevel_1-1566860281.zip

Regards,

Udhayakumar





MM Mohannad Mostafa November 12, 2024 03:13 AM UTC

Hello, 


Thank you for your help. I have attached a document of a similar exaample where we see the issue in details along with screenshots and server response.


I have also attached the backend code in the attachement and i have tried to follow almost the same code as the example you have provided.

Thank you for your help.


Attachment: serverCodeIssueDescription_f2e220b7.zip


MM Mohannad Mostafa November 12, 2024 02:17 PM UTC

Also, if you note from what Loai has previously posted, In the correct Data Row Return, there's 'parentUniqueID' and another item called `parentItem`. While on the incorrect Data Row Return, we do not get these values from the library.


in summary we have two issues described here, there's one related to incorrect order of data returned. And the other one is, even if data is returned correctly, indentation is not reflecting the actual data. We have noticed indentiation is getting messed up after 2 levels exactly or after refreshing the page


For complete reference to our code, here is a snippet of our customAdapter from the frontend:

import { UrlAdaptor } from '@syncfusion/ej2-data';
import moment from 'moment';

export class CustomGanttAdaptor extends UrlAdaptor {

// Overriding processQuery to modify API call
processQuery(dm: any, query: any, hierarchyFilters: any) {

const projectId = parseInt(dm.dataSource.url.split("=")[1]);

// Extract pagination details
const onPageQuery = query.queries.find((q: any) => q.fn === 'onPage');
const skip = onPageQuery ? (onPageQuery.e.pageIndex - 1) * onPageQuery.e.pageSize : 0;
const take = onPageQuery ? onPageQuery.e.pageSize : 22;

// Extract where (filter) conditions
const onWhereQuery = query.queries.find((q: any) => q.fn === 'onWhere');
const where = onWhereQuery ? [{
field: onWhereQuery.e.field,
operator: onWhereQuery.e.operator,
value: onWhereQuery.e.value,
ignoreCase: onWhereQuery.e.ignoreCase,
isComplex: onWhereQuery.e.isComplex
}] : [];

// Construct the payload based on the query parameters
const payload = {
skip: skip,
take: take,
requiresCounts: true,
expand: where[0]?.value == null ? null : query.expands,
where: where[0]?.value == null ? null : where,
};

const result: any = {
type: 'POST',
url: `${process.env.NEXT_PUBLIC_API_BASE_URL}/api/Project/GetTreeData?projectId=${projectId}`,
data: JSON.stringify(payload),
contentType: 'application/json'
};

return result;

}

}



and here's how we call data manager 

useEffect(() => {
if (projectId) {
const dataManager = new DataManager({
url: `${process.env.NEXT_PUBLIC_API_BASE_URL}/api/Project/GetTreeData?projectId=${projectId}`,
// adaptor: new WebApiAdaptor,
adaptor: new CustomGanttAdaptor(),
headers: [{ 'Authorization': `Bearer ${token}` }]
});
setDataManager(dataManager);
}
}, [projectId]);


and here's our GanttChart component:

<GanttComponent
ref={ganttInstance}
dataSource={dataManager}
treeColumnIndex={1}
taskFields={taskSettings}
height={"98%"}
gridLines='Vertical'
renderBaseline={true}
baselineColor='#CDD1D7'
tooltipSettings={{
showTooltip: true,
taskbar: (e: any) => taskBarTooltip(e),
baseline: (e: any) => taskBarTooltip(e)
}}
labelSettings={{
taskLabel: (e: any) => taskBarLabel(e)
}}
toolbar={toolbar}
allowFiltering={true}
timelineSettings={{
timelineUnitSize: 50
}}
queryTaskbarInfo={queryTaskbarInfo}
connectorLineBackground='#FF6633'
taskbarTemplate={(e: any) => taskbarTemplate(e)}
taskbarHeight={17}
allowResizing={true}
zoomingLevels={customZoomingLevels}
recordDoubleClick={(e: any) => handleTaskClick(e)}
toolbarClick={toolbarClick}
enableCriticalPath={enableCriticalPath}
allowParentDependency={showDependency}
autoCalculateDateScheduling={false}
enableVirtualization={true}
enableTimelineVirtualization={true}
loadChildOnDemand={true}
loadingIndicator={{ indicatorType: "Shimmer" }}
enableVirtualMaskRow={true}
splitterSettings={{ view: 'Grid' }}
>
<EventMarkersDirective>
<EventMarkerDirective day={new Date()} label='Today' cssClass='eventMarker'></EventMarkerDirective>
</EventMarkersDirective>
<ColumnsDirective>
<ColumnDirective field='taskId' headerText='ID' width='100' textAlign="Left"></ColumnDirective>
<ColumnDirective field='taskName' headerText='Name' width='300' textAlign="Left"></ColumnDirective>
<ColumnDirective field='taskName' headerText='Name' width='300' textAlign="Left" template={(e: any) => nameTemplate(e)}></ColumnDirective>
<ColumnDirective field='level' headerText='Level' width='120' textAlign="Left"></ColumnDirective>
<ColumnDirective field='progress' headerText='% Complete' width='150'></ColumnDirective>
<ColumnDirective field='duration' width='150'></ColumnDirective>
<ColumnDirective field='startDate' width='150'></ColumnDirective>
<ColumnDirective field='endDate' width='150'></ColumnDirective>
</ColumnsDirective>
<Inject services={[Selection, CriticalPath, DayMarkers, Filter, Toolbar, VirtualScroll, Resize]} />
</GanttComponent>




SJ Sridharan Jayabalan Syncfusion Team November 14, 2024 02:16 PM UTC

Mostafa,

 

Query 1 - there's one related to incorrect order of data returned.


After validating the sample, we found that the AppendChildren method had incorrect index updation, which caused an incorrect order of data being returned. We have modified the method to resolve this issue. Please refer to the code snippet and sample for reference.


Code-Snippet:   
HomeController.cs:-
private void AppendChildren(DataManagerRequest dm, List<TreeData> ChildRecords, TreeData ParentValue, Dictionary<string, List<TreeData>> GroupData, List<TreeData> data) // Getting child records for the respective parent
 {
     string TaskId = ParentValue.taskId.ToString();
     //var index = data.IndexOf(ParentValue);   // Removed the initialization of 'index'
     DataOperations operation = new DataOperations();
     foreach (var Child in ChildRecords)
     {
         if ((bool)ParentValue.IsExpanded)
         {
             string ParentId = Child.parentID.ToString();
             if (TaskId == ParentId)
             {
                 ((IList)data).Insert(++parentIndex, Child); // new modified code
                 if (GroupData.ContainsKey(Child.taskId.ToString()))
                 {
                  ....................................................................
             }
         }
     }
 }
Client Sample - client sample 
Server sample - Server sample


Query 2 - And the other one is, even if data is returned correctly, indentation is not reflecting the actual data.


We have reviewed your query, and we are able to replicate the issue "On expand parent records, data not aligned properly when loadOnDemand and Virtualization enabled" in Gantt Chart.

To address the problem, we have logged a bug request, and the fix will be provided in the patch release which is scheduled to be rolled out on December 10, 2024. You can track its status from the feedback link given below.
Note - You can view the feedback link once it moved to validated state.
Disclaimer: Inclusion of this solution in the weekly release may change due to other factors including but not limited to QA checks and works reprioritization

 

Regards,

Sridharan



SJ Sridharan Jayabalan Syncfusion Team December 13, 2024 12:53 PM UTC

Mostafa,

 

Query 2 - And the other one is, even if data is returned correctly, indentation is not reflecting the actual data.


We are glad to announce that our patch release (v27.2.5) is rolled out successfully. In this release, we have added the fix for the reported issue.


Sample - local sample will attach in forum.

Root cause - We are updating the level to 0 for all records which fetched from treegrid for load child on demand sample in createRecord method.

Release notes - Essential Studio for EJ2 TypeScript Weekly Release Release Notes



Regards,

Sridharan



SJ Sridharan Jayabalan Syncfusion Team December 13, 2024 01:25 PM UTC

Mostafa,

 

Please ignore the previous update. 


Query 2 - And the other one is, even if data is returned correctly, indentation is not reflecting the actual data.


We are glad to announce that our patch release (v27.2.5) is rolled out successfully. In this release, we have added the fix for the reported issue.

 
Please upgrade to the latest version packages to resolve this issue "On expand parent records, data not aligned properly when loadOnDemand and Virtualization enabled in React | Feedback Portal". Refer the attached sample.

Client sample - https://www.syncfusion.com/downloads/support/directtrac/general/ze/NEXTJS~117387397

Server Sample - https://www.syncfusion.com/downloads/support/directtrac/general/ze/MutliLevelLOD1619137247

Root cause - We are updating the level to 0 for all records which fetched from treegrid for load child on demand sample in createRecord method.

Release notes - Essential Studio for EJ2 TypeScript Weekly Release Release Notes



Regards,

Sridharan



JS Jaya Simha June 19, 2025 05:05 AM UTC

In React Gantt (v29.2.4), when using DataManager for remote data with lazy loading, the task hierarchy is not rendering correctly — child tasks aren't aligned under their parents as expected
Attachment: image_4_3f116955.png


SJ Sridharan Jayabalan Syncfusion Team June 19, 2025 02:09 PM UTC

Jaya,

 

For your query, we have prepared a sample and attempted to replicate the reported issue, but we were unable to reproduce it on our end.

We suspect that the issue may be caused by your backend returning incorrect data. We have attached a working sample and a video demonstration for your reference.

 

 

Refer to our attached backend code in the HomeController.cs file and modify your codes based on it and check whether the backend returns the correct data to the frontend. Also, ensure that you are using the latest version, v29.2.11, when testing.

 

If the issue still persists, kindly share the following details to proceed with validation:

 

  • Your complete backend and frontend code.
  • Type of Adaptor that you have used.
  • Ensure that you have handled the data at server end.
  • Alternatively, replicate the issue using the attached sample or provide us with a runnable sample where the issue can be reproduced.

 

Client Sample - 56acobra (duplicated) - StackBlitz

Server Sample - https://www.syncfusion.com/downloads/support/directtrac/general/ze/MutliLevelLOD

Documentation - Data binding in React Gantt component | Syncfusion

 

 

Regards,

Sridharan


Loader.
Up arrow icon