How to correctly setup a RESTful backend for UrlAdaptor (DataManager, Gantt Chart)

Dear Syncfusion Team:

I was trying to setup a DataManager (with UrlAdaptor) to the Gantt Chart.

To do this, I referred to the following documentations:

My sample implementation is:

Frontend:

  • App.vue
<script setup>
import { GanttComponent as EjsGantt } from '@syncfusion/ej2-vue-gantt';
import { DataManager, UrlAdaptor, JsonAdaptor } from '@syncfusion/ej2-data';

// Reference:
// 1. https://ej2.syncfusion.com/documentation/data/adaptors#url-adaptor
// 2. https://ej2.syncfusion.com/vue/documentation/gantt/data-binding#url-adaptor
const dataManager = new DataManager({
  url: 'http://localhost:3000/tasks',
  adaptor: new UrlAdaptor()
});

// Define task fields mapping
const taskFields = {
    id: 'TaskID',
    name: 'TaskName',
    startDate: 'StartDate',
    endDate: 'EndDate',
    progress: 'Progress',
    parentID:'ParentId'
};
</script>

<template>
  <div
    style="position:absolute; top:0; right:0; bottom:0; left:0; display:flex; flex-direction:column; overflow:hidden;">
    <!-- Gantt fills remaining space -->
    <div style="flex: 1 1 auto; min-height: 0; overflow:auto;">
      <ejs-gantt
        :taskFields="taskFields"
        :columns="columns"
        :height="'100%'"
        :dataSource="dataManager" />
    </div>
  </div>
</template>

Backend:

  • The RESTful endpoint is:
http://localhost:3000/tasks



The data returned by accessing the endpoint `http://localhost:3000/tasks` through a browser are (the format should fit the requirements stated at this link Adaptors in EJ2 TypeScript DataManager | Syncfusion ):

{
  "result":
  [
    {"TaskID":1,"TaskName":"A","StartDate":"2025-06-26T00:00:00.000Z","EndDate":"2025-06-27T09:00:00.000Z","Progress":38,"parentId":null},
...
    {"TaskID":7,"TaskName":"F","StartDate":"2025-07-23T00:00:00.000Z","EndDate":"2025-07-25T09:00:00.000Z","Progress":0,"parentId":null}
  ],
  "count":7
}

But the test result is an empty Gantt Chart (no errors or warnings in the console or log files):

Image_9938_1751378922587


But In the same project, I tried JsonAdaptor and WebApiAdaptor sample code from the Documentations simply by modifying App.vue file (no other file or configuration changed), and they both work as expected.


JsonAdaptor Code (Only those that have changed) - App.vue
Data binding in Vue Gantt component | Syncfusion
const data = [
    { TaskID: 1,TaskName: 'Project Initiation',StartDate: new Date('04/02/2019'),EndDate: new Date('04/21/2019')},
    { TaskID: 2, TaskName: 'Identify Site location', StartDate: new Date('04/02/2019'), Duration: 4, Progress: 50,ParentId:1 },
    { TaskID: 3, TaskName: 'Perform Soil test', StartDate: new Date('04/02/2019'), Duration: 4, Progress: 50, ParentId:1   },
    { TaskID: 4, TaskName: 'Soil test approval', StartDate: new Date('04/02/2019'), Duration: 4, Progress: 50,ParentId:1 },
    { TaskID: 5, TaskName: 'Project Estimation',StartDate: new Date('04/02/2019'),EndDate: new Date('04/21/2019')},
    { TaskID: 6, TaskName: 'Develop floor plan for estimation', StartDate: new Date('04/04/2019'), Duration: 3, Progress: 50, ParentId:2  },
    { TaskID: 7, TaskName: 'List materials', StartDate: new Date('04/04/2019'), Duration: 3, Progress: 50,ParentId:2  },
    { TaskID: 8, TaskName: 'Estimation approval', StartDate: new Date('04/04/2019'), Duration: 3, Progress: 50, ParentId:2  }
];


// Reference:
// 1. https://ej2.syncfusion.com/vue/documentation/gantt/data-binding#self-referential-data-binding-flat-data
// 2. https://ej2.syncfusion.com/documentation/data/adaptors#json-adaptor
const dataManager = new DataManager({
  json: data,
  adaptor: new JsonAdaptor()
});


JsonAdaptor Test Result (Same Project, Same configuration, Same Environment):

Image_6284_1751379199556


WebApiAdaptor Code (Only those that have changed) - App.vue
Data binding in Vue Gantt component | Syncfusion
// Reference: https://ej2.syncfusion.com/vue/documentation/gantt/data-binding#remote-data
const dataManager = new DataManager({
  url: 'https://services.syncfusion.com/vue/production/api/GanttData',
  adaptor: new WebApiAdaptor(),
  crossDomain: true
});


WebApiAdaptor Test Result (Same Project, Same configuration, Same Environment):

Image_9231_1751379291423


I guess there must be something wrong with my backend RESTful endpoints, please help, thanks a lot!

There are limitations on the length of the thread, i can't paste more code here.


2 Replies

RY Ryan.L July 1, 2025 02:39 PM UTC

The backend code I was about to paste is (not full code, could be verbose):

electron/main.ts

app.whenReady().then(async () => {
  await initializeDataSource();
  // --- start REST API for DataManager UrlAdaptor ---
  const api = express();
  api.use(cors());
  api.use(bodyParser.json());
  // GET all tasks
  api.get('/tasks', async (_req: Request, res: Response) => {
    const repo = dataSource.getRepository(Task);
    // load flat list of tasks
    const allTasks = await repo.find();
    // map to Gantt fields
    const nodes: any[] = allTasks.map(t => ({
      TaskID: t.id,
      TaskName: t.title,
      StartDate: t.startDate ? t.startDate.toISOString() : undefined,
      EndDate: t.endDate ? t.endDate.toISOString() : undefined,
      Duration: undefined,
      Progress: t.progress,
      parentId: t.parentId,
    }));
    // build hierarchical tree
    const map = new Map<number, any>(nodes.map(n => [n.TaskID, n]));
    const roots: any[] = [];
    nodes.forEach(n => {
      if (n.parentId != null && map.has(n.parentId)) {
        const parent = map.get(n.parentId)!;
        parent.subtasks = parent.subtasks ?? [];
        parent.subtasks.push(n);
      } else {
        roots.push(n);
      }
    });
    res.json({result: roots, count: roots.length});
  });
  // Create task
  api.post('/tasks', async (req: Request, res: Response) => {
    const repo = dataSource.getRepository(Task);
    // Map Gantt fields to Task entity properties
    const d = req.body;
    const newTask = repo.create({
      title: d.TaskName || '',
      description: d.description || '',
      startDate: d.StartDate ? new Date(d.StartDate) : undefined,
      endDate: d.EndDate ? new Date(d.EndDate) : undefined,
      progress: d.Progress ?? 0,
      parentId: d.parentId || null,
    });
    const saved = await repo.save(newTask);
    res.status(201).json({ result: [saved], count: 1 });
  });
  // Update task
  api.put('/tasks/:id', async (req: Request, res: Response) => {
    const repo = dataSource.getRepository(Task);
    const id = Number(req.params.id);
    const d = req.body;
    // Map Gantt fields to Task entity properties
    const updateData: any = {};
    if (d.TaskName !== undefined) updateData.title = d.TaskName;
    if (d.description !== undefined) updateData.description = d.description;
    if (d.StartDate !== undefined) updateData.startDate = new Date(d.StartDate);
    if (d.EndDate !== undefined) updateData.endDate = new Date(d.EndDate);
    if (d.Progress !== undefined) updateData.progress = d.Progress;
    if (d.parentId !== undefined) updateData.parentId = d.parentId;
    await repo.update(id, updateData);
    const updated = await repo.findOneBy({ id });
    res.json({ result: [updated], count: 1 });
  });
  // Delete task
  api.delete('/tasks/:id', async (req: Request, res: Response) => {
    const repo = dataSource.getRepository(Task);
    await repo.delete(Number(req.params.id));
    res.json({ result: [], count: 0 });
  });
  api.listen(3000, () => logDebug('REST API listening on http://localhost:3000'));
  // -----------------------------------------------
  createWindow();
});


AG Ajithkumar Gopalakrishnan Syncfusion Team July 3, 2025 10:59 AM UTC

Hi Ryan,

Greetings from Syncfusion Support,

We have verified the shared details on our end. When using the Gantt chart with URL Adaptor and a Node.js/Express backend, we observed that the Gantt chart does not render data when using the GET method it only displays an empty chart.

This is because, in DataManager, the EJ2 Gantt chart with UrlAdaptor sends POST requests for all actions, including data fetching and CRUD operations. Unlike GET requests, which have limitations on query string length, POST requests allow for larger payloads and are more reliable for data operations. Therefore, using POST is the recommended and more effective approach.

If you prefer to use GET requests, we recommend switching to the WebApiAdaptor, which sends GET requests for data fetching and expects the response in the following format:

"Items": a JSON array of records
"Count": the total number of records in the database

Additionally, we have prepared a Gantt chart with a URL adaptor with the backend as a Node/Express.js sample, and it is attached below. Please refer to it.

<ejs-gantt ref='gantt' id="GanttContainer"

           :dataSource="data"

           >

           ...

</ejs-gantt>

data: new DataManager({

    url: 'http://localhost:3000/tasks',

    adaptor: new UrlAdaptor(),

    crossDomain: true,

}),

taskFields: {

        id: 'TaskID',

    name: 'TaskName',

    startDate: 'StartDate',

    endDate: 'EndDate',

    duration: 'Duration',

    parentID: 'parentId',

},

// server.js

    const express = require('express');

    const cors = require('cors');

    const bodyParser = require('body-parser');

 

    const api = express();

    api.use(cors());

api.use(bodyParser.json());

 

api.post('/tasks', async(_req, res) => {

    //const dm = _req.body;

  const allTasks = [

    { TaskID: 1, TaskName: 'Project Initiation', StartDate: '2019-04-02', EndDate: '2019-04-21', parentId: null },

    { TaskID: 2, TaskName: 'Identify Site location', StartDate: '2019-04-02', Duration: 4, Progress: 50, parentId: 1 },

    { TaskID: 3, TaskName: 'Perform Soil test', StartDate: '2019-04-02', Duration: 4, Progress: 50, parentId: 1 },

    { TaskID: 4, TaskName: 'Soil test approval', StartDate: '2019-04-02', Duration: 4, Progress: 50, parentId: 1 },

    { TaskID: 5, TaskName: 'Project Estimation', StartDate: '2019-04-02', EndDate: '2019-04-21', parentId: null },

    { TaskID: 6, TaskName: 'Develop floor plan', StartDate: '2019-04-04', Duration: 3, Progress: 50, parentId: 5 },

    { TaskID: 7, TaskName: 'List materials', StartDate: '2019-04-04', Duration: 3, Progress: 50, parentId: 5 },

    { TaskID: 8, TaskName: 'Estimation approval', StartDate: '2019-04-04', Duration: 3, Progress: 50, parentId: 5 },

  ];

 

res.json({ result: allTasks, count: allTasks.length });

});

 

api.listen(3000, () => console.log('API running on http://localhost:3000'));

Client sample link: https://stackblitz.com/edit/j9n1in-ya4afkn1?file=src%2FApp.vue

Backend sample link: https://www.syncfusion.com/downloads/support/directtrac/general/ze/gantt-api

If you have any further questions or need additional assistance, please feel free to let us know!


Regards,
Ajithkumar G


Loader.
Up arrow icon