Data binding
25 Feb 202224 minutes to read
The TreeGrid uses DataManager, which supports both RESTful JSON data services binding and local JavaScript object array binding. The dataSource
property can be assigned either with the instance of DataManager or JavaScript object array collection.
It supports two kinds of data binding method:
- Local data
- Remote data
Local Data
In Local Data binding, data source for rendering the TreeGrid control is retrieved from the same application locally.
Two types of Data binding are possible with the TreeGrid control.
- Hierarchical Datasource binding
- Self-Referential Data binding (Flat Data)
To bind local data to the treegrid, 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.
By default, DataManager uses JsonAdaptor for local data-binding.
Hierarchy data source binding
The childMapping
property is used to map the child records in hierarchy data source.
The following code example shows you how to bind the hierarchical local data into the TreeGrid control.
<ejs-treegrid id="TreeGrid" dataSource="@ViewBag.data" allowPaging="true" childMapping="Children" treeColumnIndex="1">
<e-treegrid-pagesettings pageSize="7"></e-treegrid-pagesettings>
<e-treegrid-columns>
<e-treegrid-column field="TaskId" headerText="Task ID" textAlign="Right" width="90"></e-treegrid-column>
<e-treegrid-column field="TaskName" headerText="Task Name" width="180"></e-treegrid-column>
<e-treegrid-column field="StartDate" headerText=" Start Date" textAlign="Right"
format="yMd" type="date" width="90"></e-treegrid-column>
<e-treegrid-column field="Duration" headerText="Duration" textAlign="Right" width="80"></e-treegrid-column>
</e-treegrid-columns>
</ejs-treegrid>
public IActionResult Index()
{
var tree = TreeGridItems.GetDefaultData();
ViewBag.data = tree;
return View();
}
public class TreeGridItems
{
public TreeGridItems() { }
public int TaskId { get; set; }
public string TaskName { get; set; }
public DateTime StartDate { get; set; }
public int Duration { get; set; }
public List<TreeGridItems> Children { get; set; }
public static List<TreeGridItems> GetDefaultData()
{
List<TreeGridItems> BusinessObjectCollection = new List<TreeGridItems>();
TreeGridItems Record1 = null;
Record1 = new TreeGridItems()
{
TaskId = 1,TaskName = "Planning", StartDate = new DateTime(2016, 06, 07), Duration = 5, Children = new List<TreeGridItems>(),
};
TreeGridItems Child1 = new TreeGridItems()
{
TaskId = 2, TaskName = "Plan timeline", StartDate = new DateTime(2016, 06, 07), Duration = 5
};
TreeGridItems Child2 = new TreeGridItems()
{
TaskId = 3, TaskName = "Plan budget", StartDate = new DateTime(2016, 06, 07), Duration = 5
};
TreeGridItems Child3 = new TreeGridItems()
{
TaskId = 4, TaskName = "Allocate resources", StartDate = new DateTime(2016, 06, 07), Duration = 5
};
Record1.Children.Add(Child1);
Record1.Children.Add(Child2);
Record1.Children.Add(Child3);
TreeGridItems Record2 = new TreeGridItems()
{
TaskId = 6, TaskName = "Design", StartDate = new DateTime(2021, 08, 25), Duration = 3, Children = new List<TreeGridItems>()
};
TreeGridItems Child5 = new TreeGridItems()
{
TaskId = 7, TaskName = "Software Specification", StartDate = new DateTime(2021, 08, 25), Duration = 3
};
TreeGridItems Child6 = new TreeGridItems()
{
TaskId = 8, TaskName = "Develop prototype", StartDate = new DateTime(2021, 08, 25), Duration = 3
};
TreeGridItems Child7 = new TreeGridItems()
{
TaskId = 9, TaskName = "Get approval from customer", StartDate = new DateTime(2024, 06, 27), Duration = 2
};
Record2.Children.Add(Child5);
Record2.Children.Add(Child6);
Record2.Children.Add(Child7);
BusinessObjectCollection.Add(Record1);
BusinessObjectCollection.Add(Record2);
return BusinessObjectCollection;
}
}
- Remote data binding is not supported for Hierarchy Data.
Self-Referential Data binding (Flat Data)
TreeGrid is rendered from Self-Referential data structures by providing two fields, ID field and parent ID field.
-
ID Field: This field contains unique values used to identify nodes. Its name is assigned to the
idMapping
property. -
Parent ID Field: This field contains values that indicate parent nodes. Its name is assigned to the
parentIdMapping
property.
<ejs-treegrid id="TreeGrid" dataSource="@ViewBag.data" idMapping="TaskId" parentIdMapping='ParentId' allowPaging="true" treeColumnIndex="1">
<e-treegrid-pagesettings pageSize="7"></e-treegrid-pagesettings>
<e-treegrid-columns>
<e-treegrid-column field="TaskId" headerText="Task ID" textAlign="Right" width="90"></e-treegrid-column>
<e-treegrid-column field="TaskName" headerText="Task Name" width="180"></e-treegrid-column>
<e-treegrid-column field="StartDate" headerText=" Start Date" textAlign="Right"
format="yMd" type="date" width="90"></e-treegrid-column>
<e-treegrid-column field="Duration" headerText="Duration" textAlign="Right" width="80"></e-treegrid-column>
</e-treegrid-columns>
</ejs-treegrid>
public IActionResult Index()
{
var tree = TreeGridItems.GetSelfData();
ViewBag.data = tree;
return View();
}
public class TreeGridItems
{
public TreeGridItems() { }
public int TaskId { get; set; }
public string TaskName { get; set; }
public DateTime StartDate { get; set; }
public int Duration { get; set; }
public int? ParentId { get; set; }
public static List<TreeGridItems> GetSelfData()
{
List<TreeGridItems> BusinessObjectCollection = new List<TreeGridItems>();
BusinessObjectCollection.Add(new TreeGridItems()
{
TaskId = 1, TaskName = "Parent Task 1", StartDate = new DateTime(2017, 10, 23), Duration = 10, ParentId = null
});
BusinessObjectCollection.Add(new TreeGridItems()
{
TaskId = 2, TaskName = "Child task 1", StartDate = new DateTime(2017, 10, 23), Duration = 4, ParentId = 1
});
BusinessObjectCollection.Add(new TreeGridItems()
{
TaskId = 3, TaskName = "Child Task 2", StartDate = new DateTime(2017, 10, 24), Duration = 5, ParentId = 1
});
BusinessObjectCollection.Add(new TreeGridItems()
{
TaskId = 4, TaskName = "Child task 3", StartDate = new DateTime(2017, 10, 25), Duration = 6, ParentId = 1
});
BusinessObjectCollection.Add(new TreeGridItems()
{
TaskId = 5, TaskName = "Parent Task 2", StartDate = new DateTime(2017, 10, 23), Duration = 10, ParentId = null
});
BusinessObjectCollection.Add(new TreeGridItems()
{
TaskId = 6, TaskName = "Child task 1", StartDate = new DateTime(2017, 10, 23), Duration = 4, ParentId = 5
});
BusinessObjectCollection.Add(new TreeGridItems()
{
TaskId = 7, TaskName = "Child Task 2", StartDate = new DateTime(2017, 10, 24), Duration = 5, ParentId = 5
});
BusinessObjectCollection.Add(new TreeGridItems()
{
TaskId = 8, TaskName = "Child task 3", StartDate = new DateTime(2017, 10, 25), Duration = 6, ParentId = 5
});
BusinessObjectCollection.Add(new TreeGridItems()
{
TaskId = 9, TaskName = "Child task 4", StartDate = new DateTime(2017, 10, 25), Duration = 6, ParentId = 5
});
return BusinessObjectCollection;
}
}
Herewith we have provided list of reserved properties and the purpose used in TreeGrid. We recommend to avoid these reserved properties for Internal purpose(To get rid of conflicts).
Reserved keywords | Purpose |
---|---|
childRecords | Specifies the childRecords of a parentData |
hasChildRecords | Specifies whether the record contains child records |
hasFilteredChildRecords | Specifies whether the record contains filtered child records |
expanded | Specifies whether the child records are expanded |
parentItem | Specifies the parentItem of childRecords |
index | Specifies the index of current record |
level | Specifies the hierarchy level of record |
filterLevel | Specifies the hierarchy level of filtered record |
parentIdMapping | Specifies the parentID |
uniqueID | Specifies the unique ID of a record |
parentUniqueID | Specifies the parent Unique ID of a record |
checkboxState | Specifies the checkbox state of a record |
isSummaryRow | Specifies the summary of a record |
taskData | Specifies the main data |
primaryParent | Specifies the Primary data |
Remote data
To bind remote data to TreeGrid component, assign service data as an instance of DataManager to the dataSource
property. To interact with remote data source, provide the endpoint url and define the hasChildMapping
property of treegrid.
The hasChildMapping
property maps the field name in data source, that denotes whether current record holds any child records. This is useful internally to show expand icon while binding child data on demand.
The TreeGrid provides Load on Demand support for rendering remote data. The Load on demand is considered in TreeGrid for the following actions.
- Expanding root nodes.
- Navigating pages, with paging enabled in TreeGrid.
When load on demand is enabled, all the root nodes are rendered in collapsed state at initial load.
When load on demand support is enabled in TreeGrid with paging, the current or active page’s root node alone will be rendered in collapsed state. On expanding the root node, the child nodes will be loaded from the remote server.
When a root node is expanded, its child nodes are rendered and are cached locally, such that on consecutive expand/collapse actions on root node, the child nodes are loaded from the cache instead from the remote server.
Similarly, if the user navigates to a new page, the root nodes of that specific page, will be rendered with request to the remote server.
Remote Data Binding supports only Self-Referential Data and by default the
pageSizeMode
for Remote Data isRoot
mode. i.e only root node’s count will be shown in pager while using Remote Data
<ejs-treegrid id="TreeGrid" idMapping="TaskID" height="260" parentIdMapping="ParentItem" hasChildMapping="isParent" treeColumnIndex="1">
<e-data-manager url="https://ej2services.syncfusion.com/production/web-services/api/SelfReferenceData" adaptor="WebApiAdaptor" crossDomain="true"></e-data-manager>
<e-treegrid-columns>
<e-treegrid-column field="TaskID" headerText="Task ID" textAlign="Right" width="90"></e-treegrid-column>
<e-treegrid-column field="TaskName" headerText="Task Name" width="180"></e-treegrid-column>
<e-treegrid-column field="StartDate" headerText=" Start Date" textAlign="Right"
format="yMd" type="date" width="90"></e-treegrid-column>
<e-treegrid-column field="Duration" headerText="Duration" textAlign="Right" width="80"></e-treegrid-column>
</e-treegrid-columns>
</ejs-treegrid>
public IActionResult Index()
{
return View();
}
By default, DataManager uses ODataAdaptor for remote data-binding.
Based on the RESTful web services, set the corresponding adaptor to DataManager. Referhere
for more details.
Filtering and searching server-side data operations are not supported in load on demand
LoadChildOnDemand
While binding remote data to Tree Grid component, by default Tree Grid renders parent rows in collapsed state. Tree Grid provides option to load the child records also during the initial rendering itself for remote data binding by setting loadChildOnDemand
as true.
When loadChildOnDemand
is enabled parent records are rendered in expanded state.
The following code example describes the behavior of the LoadChildOnDemand feature of Tree Grid.
<ejs-treegrid id="TreeGrid" idMapping="TaskID" parentIdMapping="ParentItem" hasChildMapping="isParent" loadChildOnDemand="true" allowSorting="true" treeColumnIndex="1" height="400">
<e-data-manager url="/Home/DataSource" adaptor="UrlAdaptor"></e-data-manager>
<e-treegrid-columns>
<e-treegrid-column field="TaskID" headerText="Task ID" textAlign="Right" width="90"></e-treegrid-column>
<e-treegrid-column field="TaskName" headerText="Task Name" textAlign="Left" width="180"></e-treegrid-column>
<e-treegrid-column field="Duration" headerText="Duration" textAlign="Right" width="90"></e-treegrid-column>
<e-treegrid-column field="Progress" headerText="Progress" textAlign="Left" width="80"></e-treegrid-column>
</e-treegrid-columns>
</ejs-treegrid>
public IActionResult Index()
{
return View();
}
public IActionResult DataSource([FromBody] DataManagerRequest dm)
{
IEnumerable DataSource = TreeData.GetTree();
DataOperations operation = new DataOperations();
if (dm.Where != null && dm.Where.Count > 0) //filtering
{
DataSource = operation.PerformFiltering(DataSource, dm.Where, "and"); //perform filtering
}
if (dm.Sorted != null && dm.Sorted.Count > 0)
{
DataSource = operation.PerformSorting(DataSource, dm.Sorted); //Sorting
}
var count = TreeData.GetTree().Count();
if (dm.Skip != 0)
{
DataSource = operation.PerformSkip(DataSource, dm.Skip); //Paging
}
if (dm.Take != 0)
{
DataSource = operation.PerformTake(DataSource, dm.Take);
}
if (dm.Where != null)
{
DataSource = CollectChildRecords(DataSource, dm); // method to collect child records
}
return dm.RequiresCounts ? Json(new { result = DataSource, count = count }) : Json(DataSource);
}
public IEnumerable CollectChildRecords(IEnumerable datasource, [FromBody] DataManagerRequest dm)
{
DataOperations operation = new DataOperations();
IEnumerable DataSource = TreeData.tree; // use the total DataSource here
string IdMapping = "TaskID"; // define your IdMapping field name here
int[] TaskIds = new int[0];
foreach (var rec in datasource)
{
int taskid = (int)rec.GetType().GetProperty(IdMapping).GetValue(rec);
TaskIds = TaskIds.Concat(new int[] { taskid }).ToArray(); //get the Parentrecord Ids based on IdMapping Field
}
IEnumerable ChildRecords = null;
foreach (int id in TaskIds)
{
dm.Where[0].value = id;
IEnumerable records = operation.PerformFiltering(DataSource, dm.Where, dm.Where[0].Operator); //perform filtering to collect the childrecords based on Ids
ChildRecords = ChildRecords == null || (ChildRecords.AsQueryable().Count() == 0) ? records : ((IEnumerable<object>)ChildRecords).Concat((IEnumerable<object>)records); //concate the childrecords with dataSource
}
if (ChildRecords != null)
{
ChildRecords = CollectChildRecords(ChildRecords, dm); // repeat the operation for inner level child
if (dm.Sorted != null && dm.Sorted.Count > 0) // perform Sorting
{
ChildRecords = operation.PerformSorting(ChildRecords, dm.Sorted);
}
datasource = ((IEnumerable<object>)datasource).Concat((IEnumerable<object>)ChildRecords); //concate the childrecords with dataSource
}
return datasource;
}
Also while using LoadChildOnDemand we need to handle the child records on server end and it is applicable to CRUD operations also.
Offline Mode
On remote data binding, all treegrid actions such as paging, loading child on-demand, will be processed on server-side. To avoid postback, set the treegrid to load all data on initialization and make the actions process in client-side. To enable this behavior, use the offline property of DataManager.
<ejs-treegrid id="TreeGrid" idMapping="TaskID" height="260" parentIdMapping="ParentItem" treeColumnIndex="1">
<e-data-manager url="https://ej2services.syncfusion.com/production/web-services/api/SelfReferenceData" adaptor="WebApiAdaptor" offline="true" crossDomain="true"></e-data-manager>
<e-treegrid-columns>
<e-treegrid-column field="TaskID" headerText="Task ID" textAlign="Right" width="90"></e-treegrid-column>
<e-treegrid-column field="TaskName" headerText="Task Name" width="180"></e-treegrid-column>
<e-treegrid-column field="StartDate" headerText=" Start Date" textAlign="Right"
format="yMd" type="date" width="90"></e-treegrid-column>
<e-treegrid-column field="Duration" headerText="Duration" textAlign="Right" width="80"></e-treegrid-column>
</e-treegrid-columns>
</ejs-treegrid>
public IActionResult Index()
{
return View();
}
Custom Adaptor
You can create your own adaptor by extending the built-in adaptors. The following demonstrates custom adaptor approach and how to add a serial number for the records by overriding the built-in response processing using the processResponse method of the ODataAdaptor.
<ejs-treegrid id="TreeGrid" idMapping="TaskID" parentIdMapping="ParentItem" created="created" treeColumnIndex="1">
<e-treegrid-columns>
<e-treegrid-column field="TaskID" headerText="Task ID" textAlign="Right" width="90"></e-treegrid-column>
<e-treegrid-column field="TaskName" headerText="Task Name" width="180"></e-treegrid-column>
<e-treegrid-column field="StartDate" headerText=" Start Date" textAlign="Right"
format="yMd" type="date" width="90"></e-treegrid-column>
<e-treegrid-column field="Duration" headerText="Duration" textAlign="Right" width="80"></e-treegrid-column>
</e-treegrid-columns>
</ejs-treegrid>
<script>
function created(args) {
class SerialNoAdaptor extends ej.data.ODataAdaptor {
processResponse() {
var i = 0;
// calling base class processResponse function
var original = super.processResponse.apply(this, arguments);
// adding serial number
if (!ej.base.isNullOrUndefined(original.result)) {
original.result.forEach(function (item) { item['Sno'] = ++i });
return { result: original.result, count: original.count };
}
else
return original;
}
}
var treegrid = document.querySelector('#TreeGrid').ej2_instances[0];
treegrid.dataSource = new ej.data.DataManager({
url: "https://ej2services.syncfusion.com/production/web-services/api/SelfReferenceData",
adaptor: new SerialNoAdaptor()
});
}
</script>
public IActionResult Index()
{
return View();
}
Sending additional parameters to the server
To add a custom parameter to the data request, use the addParams method of Query class. Assign the Query object with additional parameters to the treegrid query
property.
<ejs-treegrid id="TreeGrid" idMapping="TaskID" query="new ej.data.Query().addParams('ej2treegrid', 'true')" height="260" parentIdMapping="ParentItem" treeColumnIndex="1" hasChildMapping="isParent">
<e-data-manager url="https://ej2services.syncfusion.com/production/web-services/api/SelfReferenceData" adaptor="WebApiAdaptor" crossDomain="true"></e-data-manager>
<e-treegrid-columns>
<e-treegrid-column field="TaskID" headerText="Task ID" textAlign="Right" width="90"></e-treegrid-column>
<e-treegrid-column field="TaskName" headerText="Task Name" width="180"></e-treegrid-column>
<e-treegrid-column field="StartDate" headerText=" Start Date" textAlign="Right"
format="yMd" type="date" width="90"></e-treegrid-column>
<e-treegrid-column field="Duration" headerText="Duration" textAlign="Right" width="80"></e-treegrid-column>
</e-treegrid-columns>
</ejs-treegrid>
public IActionResult Index()
{
return View();
}
Handling HTTP error
During server interaction from the treegrid, 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.
<ejs-treegrid id="TreeGrid" idMapping="TaskID" parentIdMapping="ParentItem" actionFailure="actionFailure" treeColumnIndex="1" hasChildMapping="isParent">
<e-data-manager url="http://some.com/invalidUrl"></e-data-manager>
<e-treegrid-columns>
<e-treegrid-column field="TaskID" headerText="Task ID" textAlign="Right" width="90"></e-treegrid-column>
<e-treegrid-column field="TaskName" headerText="Task Name" width="180"></e-treegrid-column>
<e-treegrid-column field="StartDate" headerText=" Start Date" textAlign="Right"
format="yMd" type="date" width="90"></e-treegrid-column>
<e-treegrid-column field="Duration" headerText="Duration" textAlign="Right" width="80"></e-treegrid-column>
</e-treegrid-columns>
</ejs-treegrid>
<script>
function actionFailure(e) {
var span = document.createElement('span');
this.element.parentNode.insertBefore(span, this.element);
span.style.color = '#FF0000'
span.innerHTML = 'Server exception: 404 Not found';
}
</script>
public IActionResult Index()
{
return View();
}
The
actionFailure
event will be triggered not only for the server errors, but also when there is an exception while processing the treegrid actions.
Binding with Ajax
You can use TreeGrid dataSource
property to bind the data source to TreeGrid 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.
<ejs-button id="updateTree" content="Update TreeGrid"></ejs-button>
<ejs-treegrid id="TreeGrid" idMapping="TaskID" parentIdMapping="ParentItem" allowPaging="true" treeColumnIndex="1" hasChildMapping="isParent">
<e-treegrid-pagesettings pageSize="7"></e-treegrid-pagesettings>
<e-treegrid-columns>
<e-treegrid-column field="TaskID" headerText="Task ID" textAlign="Right" width="90"></e-treegrid-column>
<e-treegrid-column field="TaskName" headerText="Task Name" width="180"></e-treegrid-column>
<e-treegrid-column field="StartDate" headerText=" Start Date" textAlign="Right"
format="yMd" type="date" width="90"></e-treegrid-column>
<e-treegrid-column field="Duration" headerText="Duration" textAlign="Right" width="80"></e-treegrid-column>
</e-treegrid-columns>
</ejs-treegrid>
<script>
document.getElementById("updateTree").addEventListener("click", function (e) {
var treegrid = document.getElementById('TreeGrid').ej2_instances[0];
var ajax = new ej.base.Ajax('https://ej2services.syncfusion.com/production/web-services/api/SelfReferenceData', 'GET');
treegrid.showSpinner();
ajax.send();
ajax.onSuccess = function (data) {
treegrid.hideSpinner();
treegrid.dataSource = JSON.parse(data);
};
});
</script>
public IActionResult Index()
{
return View();
}
- If you bind the dataSource from this way, then it acts like a local dataSource. So you cannot perform any server side crud actions.
You can refer to ourASP.NET Core Tree Grid
feature tour page for its groundbreaking feature representations. You can also explore our ASP.NET Core Tree Grid exampleASP.NET Core Tree Grid example
to knows how to present and manipulate data.