Search results

Data Binding in JavaScript (ES5) Gantt control

17 Mar 2023 / 9 minutes to read

The Gantt control uses DataManager for binding the data source, which supports both RESTful JSON data services and local JavaScript object array. The dataSource property can be assigned either with the instance of DataManager or JavaScript object array collection. The Gantt control supports binding two types of data:

  • Local data
  • Remote data

Local data

To bind local data to Gantt, you can assign a JavaScript object array to the dataSource property. The local data source can also be provided as an instance of the DataManager.

In local data binding, the data source for rendering the Gantt control is retrieved from the same application locally.

The following are the two types of data binding possible with the Gantt control:

  • Hierarchical data binding.
  • Self-referential data binding (Flat data).

Hierarchical data binding

The child property is used to map the child records in hierarchical data.

The following code example shows how to bind the hierarchical local data into the Gantt control.

Source
Preview
index.js
index.html
Copied to clipboard
var GanttData = [
        {
            TaskID: 1,
            TaskName: 'Project Initiation',
            StartDate: new Date('04/02/2019'),
            EndDate: new Date('04/21/2019'),
            subtasks: [
                { TaskID: 2, TaskName: 'Identify Site location', StartDate: new Date('04/02/2019'), Duration: 4, Progress: 50 },
                { TaskID: 3, TaskName: 'Perform Soil test', StartDate: new Date('04/02/2019'), Duration: 4, Progress: 50  },
                { TaskID: 4, TaskName: 'Soil test approval', StartDate: new Date('04/02/2019'), Duration: 4, Progress: 50 },
            ]
        },
        {
            TaskID: 5,
            TaskName: 'Project Estimation',
            StartDate: new Date('04/02/2019'),
            EndDate: new Date('04/21/2019'),
            subtasks: [
                { TaskID: 6, TaskName: 'Develop floor plan for estimation', StartDate: new Date('04/04/2019'), Duration: 3, Progress: 50 },
                { TaskID: 7, TaskName: 'List materials', StartDate: new Date('04/04/2019'), Duration: 3, Progress: 50 },
                { TaskID: 8, TaskName: 'Estimation approval', StartDate: new Date('04/04/2019'), Duration: 3, Progress: 50 }
            ]
        },
    ];
	
var ganttChart = new ej.gantt.Gantt({
        dataSource: GanttData,
		height:'450px',
		taskFields: {
            id: 'TaskID',
            name: 'TaskName',
            startDate: 'StartDate',
			duration: 'Duration',
            progress: 'Progress',
			child: 'subtasks'
        }
});
ganttChart.appendTo('#Gantt');
Copied to clipboard
<!DOCTYPE html><html lang="en"><head>
            
    <title>EJ2 Gantt</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Typescript Gantt Controls">
    <meta name="author" content="Syncfusion">
    <link href="index.css" rel="stylesheet">
	<link href="https://cdn.syncfusion.com/ej2/20.4.48/material.css" rel="stylesheet" type="text/css">
    
    
<script src="https://cdn.syncfusion.com/ej2/20.4.48/dist/ej2.min.js" type="text/javascript"></script>
</head>

<body>
       
    
    <div id="container">
        <div id="Gantt"></div>        
    </div>


<script>
var ele = document.getElementById('container');
if(ele) {
    ele.style.visibility = "visible";
 }   
        </script>
<script src="index.js" type="text/javascript"></script>
</body></html>

Self-referential data binding (Flat data)

The Gantt control can be bound with self-referential data by mapping the data source field values to the id and parentID properties.

  • ID field: This field contains unique values used to identify each individual task and it is mapped to the id property.
  • Parent ID field: This field contains values that indicate parent tasks and it is mapped to the parentID property.
Source
Preview
index.js
index.html
Copied to clipboard
var SelfReferenceData = [
            { 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:5  },
            { TaskID: 7, TaskName: 'List materials', StartDate: new Date('04/04/2019'), Duration: 3, Progress: 50,ParentId:5  },
            { TaskID: 8, TaskName: 'Estimation approval', StartDate: new Date('04/04/2019'), Duration: 3, Progress: 50, ParentId:5  }
        ];
var ganttChart = new ej.gantt.Gantt({
        dataSource: SelfReferenceData,
		height:'450px',
		taskFields: {
            id: 'TaskID',
            name: 'TaskName',
            startDate: 'StartDate',
			duration: 'Duration',
            progress: 'Progress',
		    parentID:'ParentId'
        }
});
ganttChart.appendTo('#Gantt');
Copied to clipboard
<!DOCTYPE html><html lang="en"><head>
            
    <title>EJ2 Gantt</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Typescript Gantt Controls">
    <meta name="author" content="Syncfusion">
    <link href="index.css" rel="stylesheet">
	<link href="https://cdn.syncfusion.com/ej2/20.4.48/material.css" rel="stylesheet" type="text/css">
    
    
<script src="https://cdn.syncfusion.com/ej2/20.4.48/dist/ej2.min.js" type="text/javascript"></script>
</head>

<body>
       
    
    <div id="container">
        <div id="Gantt"></div>        
    </div>


<script>
var ele = document.getElementById('container');
if(ele) {
    ele.style.visibility = "visible";
 }   
        </script>
<script src="index.js" type="text/javascript"></script>
</body></html>

Remote data

To bind remote data to the Gantt component, assign service data as an instance of DataManager to the dataSource property.

Source
Preview
index.js
index.html
Copied to clipboard
var hostUrl = 'https://ej2services.syncfusion.com/production/web-services/';
    var GanttData = new ej.data.DataManager({
        url: hostUrl + 'api/GanttData',
        adaptor: new ej.data.WebApiAdaptor(),
        crossDomain: true
    });
var ganttChart = new ej.gantt.Gantt({
        dataSource: GanttData,
		height:'450px',
		taskFields: {
            id: 'TaskId',
            name: 'TaskName',
            startDate: 'StartDate',
            duration: 'Duration',
            dependency: 'Predecessor',
            child: 'SubTasks'
        }
});
ganttChart.appendTo('#Gantt');
Copied to clipboard
<!DOCTYPE html><html lang="en"><head>
            
    <title>EJ2 Gantt</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Typescript Gantt Controls">
    <meta name="author" content="Syncfusion">
    <link href="index.css" rel="stylesheet">
	<link href="https://cdn.syncfusion.com/ej2/20.4.48/material.css" rel="stylesheet" type="text/css">
    
    
<script src="https://cdn.syncfusion.com/ej2/20.4.48/dist/ej2.min.js" type="text/javascript"></script>
</head>

<body>
       
    
    <div id="container">
        <div id="Gantt"></div>        
    </div>


<script>
var ele = document.getElementById('container');
if(ele) {
    ele.style.visibility = "visible";
 }   
        </script>
<script src="index.js" type="text/javascript"></script>
</body></html>

URL Adaptor

In Gantt, we can fetch data from SQL database using ADO.NET Entity Data Model and update the changes on CRUD action to the server by using DataManager support. To communicate with the remote data we are using UrlAdaptor of DataManager property to call the server method and get back resultant data in JSON format. We can know more about UrlAdaptor from here.

Please refer the link to create the ADO.NET Entity Data Model in Visual studio,

We can define data source for Gantt as instance of DataManager using url property of DataManager. Please Check the below code snippet to assign data source to Gantt.

Copied to clipboard
var dataSource = new ej.data.DataManager({
url: '/Home/UrlDatasource',
adaptor: new ej.data.UrlAdaptor
});

var gantt = new ej.gantt.Gantt({
dataSource: dataSource,
height: '450px',
treeColumnIndex: 1,
taskFields: {
    id: 'TaskId',
    name: 'TaskName',
    startDate: 'StartDate',
    progress: 'Progress',
    duration: 'Duration',
    dependency: 'Predecessor',
    child: 'SubTasks'
}
});
gantt.appendTo('#Gantt');
Copied to clipboard
GanttDataSourceEntities db = new GanttDataSourceEntities();
public ActionResult UrlDatasource(DataManagerRequest dm)
{
List<GanttData>DataList = db.GanttDatas.ToList();
var count = DataList.Count();
return Json(new { result = DataList, count = count });
}

Remote Save Adaptor

You may need to perform all Gantt Actions on the client-side except the CRUD operations, that should be interacted with the server-side to persist data. It can be achieved in Gantt by using RemoteSaveAdaptor.

Datasource must be set to the json property and set RemoteSaveAdaptor to the adaptor property. CRUD operations can be mapped to the server-side by using the batchUrl properties.

You can use the following code example to use RemoteSaveAdaptor in Gantt.

Copied to clipboard
ej.gantt.Gantt.Inject(ej.gantt.Toolbar, ej.gantt.Selection, ej.gantt.Edit);

var dataSource = new ej.data.DataManager({
json: data,
adaptor: new ej.data.RemoteSaveAdaptor,
batchUrl: 'Home/BatchUpdate'
});

var gantt = new ej.gantt.Gantt({
dataSource: dataSource,
height: '450px',
toolbar: ['Add', 'Edit', 'Update', 'Delete', 'Cancel', 'ExpandAll', 'CollapseAll', 'Indent', 'Outdent'],
taskFields: {
    id: 'taskId',
    name: 'taskName',
    startDate: 'startDate',
    duration: 'duration',
    progress: 'progress',
    parentID: 'parentID',
    dependency: 'predecessor',
},
editSettings: {
    allowAdding: true,
    allowEditing: true,
    allowDeleting: true,
    allowTaskbarEditing: true,
    showDeleteConfirmDialog: true
},
});
gantt.appendTo('#Gantt');

The following code example describes the CRUD operations handled at server-side.

Copied to clipboard
public IActionResult BatchUpdate([FromBody] CRUDModel batchmodel)
{
    public class CRUDModel
    {
        public List<GanttDataSource> added { get; set; }
        public List<GanttDataSource> changed { get; set; }
        public List<GanttDataSource> deleted { get; set; }
        public object key { get; set; }
        public string action { get; set; }
        public string table { get; set; }
    }

    public IActionResult BatchUpdate([FromBody] CRUDModel batchmodel)
    {
        if (batchmodel.changed != null)
        {
            for (var i = 0; i < batchmodel.changed.Count(); i++)
            {
                var value = batchmodel.changed[i];
                GanttDataSource result = DataList.Where(or => or.taskId == value.taskId).FirstOrDefault();
                result.taskId = value.taskId;
                result.taskName = value.taskName;
                result.startDate = value.startDate;
                result.endDate = value.endDate;
                result.duration = value.duration;
                result.progress = value.progress;
                result.parentID = value.parentID;
            }
        }
        if (batchmodel.deleted != null)
        {
            for (var i = 0; i < batchmodel.deleted.Count(); i++)
            {
                DataList.Remove(DataList.Where(or => or.taskId.Equals(batchmodel.deleted[i].taskId)).FirstOrDefault());
                RemoveChildRecords(batchmodel.deleted[i].taskId);
            }
        }
        if (batchmodel.added != null)
        {
            for (var i = 0; i < batchmodel.added.Count(); i++)
            {
                DataList.Add(batchmodel.added[i]);
            }
        }
        return Json(new { addedRecords = batchmodel.added, changedRecords = batchmodel.changed, deletedRecords = batchmodel.deleted });
    }

   public void RemoveChildRecords(int key)
    {
        var childList = DataList.Where(x => x.parentID == key).ToList();
        foreach (var item in childList)
        {
            DataList.Remove(item);
            RemoveChildRecords(item.taskId);
        }
    }
    return Json(new { addedRecords = batchmodel.added, changedRecords = batchmodel.changed, deletedRecords = batchmodel.deleted });
}

Sending additional parameters to the server

We can pass additional parameters using addParams method of Query class. In server side we have inherited and shown the additional parameter value in Syncfusion DataManager class itself. We pass an additional parameter in load time using load event. We can also pass additional parameter to the CRUD model. Please Check the below code snippet to send additional parameter to Gantt.

Copied to clipboard
ej.gantt.Gantt.Inject(ej.gantt.Toolbar, ej.gantt.Selection, ej.gantt.Edit);

var dataSource = new ej.data.DataManager({
url: 'http://localhost:50039/Home/UrlDatasource',
adaptor: new ej.data.UrlAdaptor,
batchUrl: 'http://localhost:50039/Home/BatchSave',
});

var gantt = new ej.gantt.Gantt({
dataSource: dataSource,
height: '450px',
treeColumnIndex: 1,
taskFields: {
  id: 'taskID',
  name: 'taskName',
  startDate: 'startDate',
  endDate: 'endDate',
  duration: 'duration',
  progress: 'progress',
  parentID: 'parentID',
},
editSettings: {
  allowAdding: true,
  allowEditing: true,
  allowDeleting: true,
},
toolbar: ['Add', 'Edit', 'Update', 'Delete', 'Cancel', 'ExpandAll', 'CollapseAll'],
load: function (args) {
  this.query = new Query().addParams('ej2Gantt', "test");
}
});
gantt.appendTo('#Gantt');
Copied to clipboard
namespace URLAdaptor.Controllers
{
public class HomeController : Controller
{
    ...///
    //inherit the class to show age as property of DataManager
    public class Test : DataManagerRequest
    {
        public string ej2Gantt { get; set; }
    }

    public ActionResult UrlDatasource([FromBody]Test dm)
    {
        if (DataList == null)
        {
            ProjectData datasource = new ProjectData();
            DataList = datasource.GetUrlDataSource();
        }
        var count = DataList.Count();
        return Json(new { result = DataList, count = count }, JsonRequestBehavior.AllowGet);
    }

    ...///

    public class ICRUDModel<T> where T : class
    {

        public object key { get; set; }

        public T value { get; set; }

        public List<T> added { get; set; }

        public List<T> changed { get; set; }

        public List<T> deleted { get; set; }

        public IDictionary<string, object> @params { get; set; }

    }
    ...///
}
}

You can find the full sample from here.

Handling HTTP error

During server interaction from the Gantt, some server-side exceptions may occur, and you can acquire those error messages or exception details in client-side using the actionFailure event.

The argument passed to the actionFailure event contains the error details returned from the server.

Source
Preview
index.js
index.html
Copied to clipboard
var dataSource = new ej.data.DataManager({
    url: 'http://some.com/invalidUrl',
});

var gantt = new ej.gantt.Gantt({
    dataSource: dataSource,
    height: '450px',
    treeColumnIndex: 1,
    taskFields: {
      id: 'taskID',
      name: 'taskName',
      startDate: 'startDate',
      endDate: 'endDate',
      duration: 'duration',
      progress: 'progress',
      parentID: 'parentID',
    },
    actionFailure: (e) => {
       let span: HTMLElement = document.createElement('span');
       gantt.element.parentNode.insertBefore(span, gantt.element);
       span.style.color = '#FF0000'
       span.innerHTML = 'Server exception: 404 Not found';
    },
});
gantt.appendTo('#Gantt');
Copied to clipboard
<!DOCTYPE html><html lang="en"><head>
            
    <title>EJ2 Gantt</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Typescript Gantt Controls">
    <meta name="author" content="Syncfusion">
    <link href="index.css" rel="stylesheet">
	<link href="https://cdn.syncfusion.com/ej2/20.4.48/material.css" rel="stylesheet" type="text/css">
    
    
<script src="https://cdn.syncfusion.com/ej2/20.4.48/dist/ej2.min.js" type="text/javascript"></script>
</head>

<body>
       
    
    <div id="container">
        <div id="Gantt"></div>        
    </div>


<script>
var ele = document.getElementById('container');
if(ele) {
    ele.style.visibility = "visible";
 }   
        </script>
<script src="index.js" type="text/javascript"></script>
</body></html>

Binding with Ajax

You can use Gantt dataSource property to bind the data source to Gantt from external Ajax request. In the below code we have fetched the data source from the server with the help of Ajax request and provided that to dataSource property by using onSuccess event of the Ajax.

Source
Preview
index.js
index.html
Copied to clipboard
var gantt = new ej.gantt.Gantt({
    height: '450px',
    treeColumnIndex: 1,
    taskFields: {
      id: 'TaskId',
      name: 'TaskName',
      startDate: 'StartDate',
      progress: 'Progress',
      duration: 'Duration',
      dependency: 'Predecessor',
      child: 'SubTasks'
    },
    projectStartDate: new Date('02/24/2019'),
    projectEndDate: new Date('07/20/2019')
});
    
gantt.appendTo('#Gantt');

let button = document.createElement('button');
button.textContent = 'Bind Data';
gantt.element.parentNode.insertBefore(button, gantt.element);
button.addEventListener("click", function(e){
    let ajax = new ej.base.Ajax("https://ej2services.syncfusion.com/production/web-services/api/GanttData","GET");
    gantt.showSpinner();
    ajax.send();
    ajax.onSuccess = function (data) {
        gantt.hideSpinner();
        gantt.dataSource = (JSON.parse(data)).Items;
    };
});
Copied to clipboard
<!DOCTYPE html><html lang="en"><head>
            
    <title>EJ2 Gantt</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Typescript Gantt Controls">
    <meta name="author" content="Syncfusion">
    <link href="index.css" rel="stylesheet">
	<link href="https://cdn.syncfusion.com/ej2/20.4.48/material.css" rel="stylesheet" type="text/css">
    
    
<script src="https://cdn.syncfusion.com/ej2/20.4.48/dist/ej2.min.js" type="text/javascript"></script>
</head>

<body>
       
    
    <div id="container">
        <div id="Gantt"></div>        
    </div>


<script>
var ele = document.getElementById('container');
if(ele) {
    ele.style.visibility = "visible";
 }   
        </script>
<script src="index.js" type="text/javascript"></script>
</body></html>

Note: If you bind the dataSource from this way, then it acts like a local dataSource. So you cannot perform any server side crud actions.

Split task

The Split-task feature allows you to split a task or interrupt the work during planned or unforeseen circumstances. We can split the task either in load time or dynamically, by defining the segments either in hierarchical or self-referential way.

Hierarchical

To split a task at load time in hierarchical way, we need to define the segment details in datasource and this field should be mapped by using the taskFields.segments property.

Copied to clipboard
[
{
    TaskID: 1, TaskName: 'Identify Site location', StartDate: new Date('04/02/2019'), Duration: 4, Progress: 50,
    Segments: [
        { StartDate: new Date("04/02/2019"), Duration: 2 },
        { StartDate: new Date("04/04/2019"), Duration: 2 }
    ]
}
]
Source
Preview
index.js
index.html
Copied to clipboard
var ganttChart = new ej.gantt.Gantt({
        dataSource: GanttData,
		height: "450px",
        taskFields: {
            id: "TaskID",
            name: "TaskName",
            startDate: "StartDate",
            endDate: "EndDate",
            duration: "Duration",
            progress: "Progress",
            child: "subtasks",
            segments: "Segments"
        },
});
ganttChart.appendTo('#Gantt');
Copied to clipboard
<!DOCTYPE html><html lang="en"><head>
            
    <title>EJ2 Gantt</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Typescript Gantt Controls">
    <meta name="author" content="Syncfusion">
    <link href="index.css" rel="stylesheet">
	<link href="https://cdn.syncfusion.com/ej2/20.4.48/material.css" rel="stylesheet" type="text/css">
    
    
<script src="https://cdn.syncfusion.com/ej2/20.4.48/dist/ej2.min.js" type="text/javascript"></script>
<script src="es5-datasource.js" type="text/javascript"></script>
</head>

<body>
    
    <div id="container">
        <div id="Gantt"></div>        
    </div>


<script>
var ele = document.getElementById('container');
if(ele) {
    ele.style.visibility = "visible";
 }   
        </script>
<script src="index.js" type="text/javascript"></script>
</body></html>

Self-referential

We can also define segment details as a flat data and this collection can be mapped by using segmentData property. The segment id field of this collection is mapped by using the taskFields.segmentId property.

Copied to clipboard
  taskFields: {
segmentId: "segmentId"
  },
  segmentData: [
{ segmentId: 1, StartDate: new Date("02/04/2019"), Duration: 2 },
{ segmentId: 1, StartDate: new Date("02/05/2019"), Duration: 5 },
{ segmentId: 4, StartDate: new Date("04/02/2019"), Duration: 2 },
{ segmentId: 4, StartDate: new Date("04/04/2019"), Duration: 2 }
  ],
Source
Preview
index.js
index.html
Copied to clipboard
var ganttChart = new ej.gantt.Gantt({
    dataSource: SplitTaskData,
    height: "450px",
    taskFields: {
        id: "TaskID",
        name: "TaskName",
        startDate: "StartDate",
        endDate: "EndDate",
        duration: "Duration",
        progress: "Progress",
        child: "subtasks",
         segmentId: "segmentId"
  },
  segmentData: [
    { segmentId: 2, StartDate: new Date("04/02/2019"), Duration: 2 },
    { segmentId: 2, StartDate: new Date("04/04/2019"), Duration: 2 },
    { segmentId: 4, StartDate: new Date("04/02/2019"), Duration: 2 },
    { segmentId: 4, StartDate: new Date("04/04/2019"), Duration: 2 }
  ],
});
ganttChart.appendTo('#Gantt');
Copied to clipboard
<!DOCTYPE html><html lang="en"><head>
            
    <title>EJ2 Gantt</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Typescript Gantt Controls">
    <meta name="author" content="Syncfusion">
    <link href="index.css" rel="stylesheet">
	<link href="https://cdn.syncfusion.com/ej2/20.4.48/material.css" rel="stylesheet" type="text/css">
    
    
<script src="https://cdn.syncfusion.com/ej2/20.4.48/dist/ej2.min.js" type="text/javascript"></script>
<script src="es5-datasource.js" type="text/javascript"></script>
</head>

<body>
    
    <div id="container">
        <div id="Gantt"></div>        
    </div>


<script>
var ele = document.getElementById('container');
if(ele) {
    ele.style.visibility = "visible";
 }   
        </script>
<script src="index.js" type="text/javascript"></script>
</body></html>

Note: Segment id field contains id of a task which should be splitted at load time.

Limitations

Gantt has the support for both Hierarchical and Self-Referential data binding. When rendering the Gantt control with SQL database, we suggest you to use the Self-Referential data binding to maintain the parent-child relation. Because the complex json structure is very difficult to manage it in SQL tables, we need to write a complex queries and we have to write a complex algorithm to find out the proper record details while updating/deleting the inner level task in Gantt data source. We cannot implement both data binding for Gantt control and this is not a recommended way. If both child and parentID are mapped, the records will not render properly because, when task id of a record defined in the hierarchy structure is assigned to parent id of another record, in such case the records will not properly render. As the self-referential will search the record with particular id in flat data only, not in the inner level of records. If we map the parentID field, it will be prioritized and Gantt will be rendered based on the parentID values.