Local Data Binding in EJ2 JavaScript Data Grid
01 Oct 202624 minutes to read
The Data Grid provides a straightforward way to bind local data, such as arrays or JSON objects, to the grid component. This feature allows data to be displayed and manipulated within the grid without the need for external server calls, making it particularly useful for scenarios involving static or locally stored data.
Assign an array of JavaScript objects to the dataSource property.
The following example demonstrates the local data binding feature in the grid:
var grid = new ej.grids.Grid({
dataSource: data.slice(0, 7),
columns: [
{ field: 'OrderID', headerText: 'Order ID', textAlign: 'Right', width: 120 },
{ field: 'CustomerID', headerText: 'Customer ID',width: 150 },
{ field: 'ShipCity', headerText: 'Ship City',width: 150 },
{ field: 'ShipName', headerText: 'Ship Name',width: 150 }
]
});
grid.appendTo('#Grid');<!DOCTYPE html><html lang="en"><head>
<title>EJ2 Grid</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Typescript Grid Control">
<meta name="author" content="Syncfusion">
<link href="index.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/35.1.37/material3.css" rel="stylesheet" />
<script src="https://cdn.syncfusion.com/ej2/35.1.37/dist/ej2.min.js" type="text/javascript"></script>
<script src="es5-datasource.js" type="text/javascript"></script>
</head>
<body>
<div id="container">
<div id="Grid"></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 data from Excel files
The Data Grid supports importing data from Excel files for display and manipulation within the grid. This streamlines transferring Excel data into a web-based environment. Use the Uploader component’s change event to handle the import.
To bind data from an Excel file to a Data Grid control, including the xlsx library via a script tag in an HTML page
<script type="text/javascript" src="https://unpkg.com/[email protected]/dist/xlsx.full.min.js"></script>To import Excel data into the grid, the following steps can be used:
- Import the Excel file using the Uploader control.
- Parse the Excel file data using the
XLSXlibrary. - Bind the JSON to the grid control.
The following example demonstrates importing Excel data into the grid by utilizing the Uploader control’s change event along with the XLSX library:
let path = {
saveUrl:
'https://services.syncfusion.com/js/production/api/FileUploader/Save',
removeUrl:
'https://services.syncfusion.com/js/production/api/FileUploader/Remove',
};
function onRemove(args) {
grid.dataSource = [''];
grid.columns = [];
}
function onSuccess(args) {
var files = args.file;
if (files) {
parseExcel(files[0]);
}
}
var dropElement = document.getElementsByClassName('control-fluid')[0];
var uploadObject = new ej.inputs.Uploader({
asyncSettings: path,
removing: onRemove,
change: onSuccess,
dropArea: dropElement,
});
uploadObject.appendTo('#fileupload');
var grid = new ej.grids.Grid({});
grid.appendTo('#Grid');
function parseExcel(file) {
if (file && file.type == 'xlsx') {
var reader = new FileReader();
reader.onload = (e) => {
var data = (e.target).result;
var workbook = XLSX.read(data, { type: 'array' });
workbook.SheetNames.forEach((sheetName) => {
var XL_row_object = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName]);
if (Array.isArray(XL_row_object) && XL_row_object.length > 0) {
grid.dataSource = XL_row_object;
} else {
dialog.content = "Invalid JSON";
dialog.show();
}
});
};
reader.readAsArrayBuffer(file.rawFile);
} else {
dialog.content = 'Please upload only .xlsx format';
dialog.show();
}
}
var dialog = new ej.popups.Dialog({
content: 'Invalid JSON',
width: 350,
visible: false,
header: 'Alert',
showCloseIcon: true,
});
dialog.appendTo('#dialog');<!DOCTYPE html><html lang="en"><head>
<title>EJ2 Grid</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Typescript Grid Control">
<meta name="author" content="Syncfusion">
<link href="index.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/35.1.37/material3.css" rel="stylesheet" />
<script src="https://cdn.syncfusion.com/ej2/35.1.37/dist/ej2.min.js" type="text/javascript"></script>
<script type="text/javascript" src="https://unpkg.com/[email protected]/dist/xlsx.full.min.js"></script>
</head>
<body>
<div id="container">
<label style="padding:20px 0px 20px 0px">Browse excel file to load and return grid</label>
<input type="file" id="fileupload" name="UploadFiles"/>
<div id="Grid"></div>
<div id="dialog"></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>CRUD operations using Fetch requests
The Data Grid provides a seamless way to bind data from external sources using Fetch requests, facilitating CRUD (Create, Read, Update, Delete) operations with data retrieved from a server. This feature is particularly valuable for sending data to a server for database updates and for asynchronously retrieving data without refreshing the entire web page.
To achieve data binding and perform CRUD actions using Fetch requests in the grid, follow these steps:
Step 1: To create a new ASP.NET Core Web API project named FetchRequest, follow these steps:
- Open Visual Studio.
- Select “Create a new project”
- Choose ASP.NET Core Web API project template.
- Name the project FetchRequest.
- Click “Create”
Step 2: Comment out the below line in launchSettings.json:
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
// "launchUrl": "swagger",
"applicationUrl": "https://localhost:xxxx;http://localhost:xxxx",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},Step 3: In the Program.cs file, add the following code:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.UseDefaultFiles();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Grid}/{action=Index}");
app.UseStaticFiles();
app.MapControllers();
app.Run();Step 4: Create a folder named wwwroot in the project root directory. This folder will contain static files served by the web server.
Step 5: Create an index.html file under the wwwroot folder and add the following code:
<!DOCTYPE html>
<html lang="en">
<head>
<title>EJ2 Grid</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Javascript Grid Control">
<meta name="author" content="Syncfusion">
<link href="https://cdn.syncfusion.com/ej2/35.1.37/material3.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
<script src="https://cdn.syncfusion.com/ej2/35.1.37/dist/ej2.min.js" type="text/javascript"></script>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type="text/javascript"></script>
</head>
<body>
<div class='col-md-9'>
<div style="padding-bottom: 10px; padding-top:10px">
<button ejs-button id="buttons" cssClass="e-small"></button>
</div>
<div id="container">
<div id="Grid"></div>
</div>
</div>
<script src="js/index.js" type="text/javascript"></script>
</body>
</html>Step 6: Create a js folder under the wwwroot folder, then create an index.js file within the js folder and follow the steps below:
A. To bind data from an external Fetch request, utilize the dataSource property of the grid. Fetch data from the server and provide it to the dataSource property using the onSuccess event of the Fetch request.
B. To perform CRUD actions, leverage the actionBegin event. The default CRUD operations can be canceled by utilizing the cancel argument provided by this event. This enables a dynamic call to the server-side method using Fetch, along with the relevant data received from the actionBegin event, to update server data accordingly.
C. In the Fetch success event, the grid endEdit and deleteRecord methods can be used to handle the addition, editing, and deletion of corresponding data in the grid. However, invoking these methods triggers the actionBegin event once again to save the changes in the grid. To prevent this behavior and maintain control over the execution flow, a flag variable can be employed and managed within the actionComplete and Fetch failure events: The following code snippet demonstrates this approach:
var grid = new ej.grids.Grid({
toolbar: ['Add', 'Edit', 'Delete', 'Update', 'Cancel'],
allowPaging: true,
actionBegin: actionBegin,
actionComplete: actionComplete,
editSettings: { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Normal' },
columns: [
{ field: 'OrderID', headerText: 'Order ID', textAlign: 'Right', width: 120, isPrimaryKey: true, type: 'number' },
{ field: 'CustomerID', width: 140, headerText: 'Customer ID', type: 'string' },
{ field: 'ShipCity', headerText: 'ShipCity', width: 140 },
{ field: 'ShipCountry', headerText: 'ShipCountry', width: 140 }
]
});
grid.appendTo('#Grid');
var button = new ej.buttons.Button({
content: 'Bind data via Fetch',
cssClass: 'e-success'
});
button.appendTo('#buttons');
let flag = false;
document.getElementById('buttons').onclick = function () {
const fetchRequest = new ej.base.Fetch("https://localhost:****/Grid/Getdata", 'POST'); //Use remote server host instead number ****
fetchRequest.send();
fetchRequest.onSuccess = (data) => {
grid.dataSource = data;
};
};
function actionComplete(e) {
if (e.requestType === 'save' || e.requestType === 'delete') {
flag = false;
}
}
function actionBegin(e) {
if (!flag) {
if (e.requestType == 'save' && (e.action == 'add')) {
var editedData = e.data;
e.cancel = true;
var fetchRequest = new ej.base.Fetch({
url: 'https://localhost:****/Grid/Insert',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ value: editedData })
});//Use remote server host instead number ****
fetchRequest.onSuccess = () => {
flag = true;
grid.endEdit();
};
fetchRequest.onFailure = () => {
flag = false;
};
fetchRequest.send();
}
if (e.requestType == 'save' && (e.action == "edit")) {
var editedData = e.data;
e.cancel = true;
var fetchRequest = new ej.base.Fetch({
url: 'https://localhost:****/Grid/Update',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ value: editedData })
}); //Use remote server host instead number ****
fetchRequest.onSuccess = () => {
flag = true;
grid.endEdit();
};
fetchRequest.onFailure = () => {
flag = false;
};
fetchRequest.send();
}
if (e.requestType == 'delete') {
var editedData = e.data;
e.cancel = true;
var fetchRequest = new ej.base.Fetch({
url: 'https://localhost:****/Grid/Delete',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ key: editedData[0][grid.getPrimaryKeyFieldNames()[0]] })
});//Use remote server host instead number ****
fetchRequest.onSuccess = () => {
flag = true;
grid.deleteRecord();
};
fetchRequest.onFailure = () => {
flag = false;
};
fetchRequest.send();
}
}
}Step 7: Create a GridController.cs file in the Controllers folder. On the server side, there is a method named GetData within the GridController that provides the data source for the grid. When the button is clicked, a Fetch request is sent to retrieve the data from the server and bind it to the grid. Additionally, implement server-side logic to perform add, edit, and delete operations.
using FetchRequest.Models;
using Microsoft.AspNetCore.Mvc;
namespace FetchRequest.Controllers
{
public class GridController : Controller
{
public ActionResult Getdata()
{
var DataSource = OrdersDetails.GetAllRecords();
return Json(DataSource);
}
//update the record in server side
public ActionResult Update([FromBody] CRUDModel<OrdersDetails> value)
{
var ord = value.value;
OrdersDetails val = OrdersDetails.GetAllRecords().Where(or => or.OrderID == ord.OrderID).FirstOrDefault();
val.OrderID = ord.OrderID;
val.EmployeeID = ord.EmployeeID;
val.CustomerID = ord.CustomerID;
val.Freight = ord.Freight;
val.OrderDate = ord.OrderDate;
val.ShipCity = ord.ShipCity;
val.ShipCountry = ord.ShipCountry;
return Json(value.value);
}
//insert the record
public ActionResult Insert([FromBody] CRUDModel<OrdersDetails> value)
{
OrdersDetails.GetAllRecords().Insert(0, value.value);
return Json(value.value);
}
//Delete the record
public ActionResult Delete(int key)
{
OrdersDetails.GetAllRecords().Remove(OrdersDetails.GetAllRecords().Where(or => or.OrderID == key).FirstOrDefault());
var data = OrdersDetails.GetAllRecords();
return Json(data);
}
}
}
public class CRUDModel<T> where T : class
{
public string action { get; set; }
public string table { get; set; }
public string keyColumn { get; set; }
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; }
}Step 8: Create a model class named OrdersDetails.cs under the Models folder in the server-side project to represent the order data.
namespace FetchRequest.Models
{
public class OrdersDetails
{
public static List<OrdersDetails> order = new List<OrdersDetails>();
public OrdersDetails()
{
}
public OrdersDetails(
int OrderID, string CustomerId, int EmployeeId, double Freight, bool Verified,
DateTime OrderDate, string ShipCity, string ShipName, string ShipCountry,
DateTime ShippedDate, string ShipAddress)
{
this.OrderID = OrderID;
this.CustomerID = CustomerId;
this.EmployeeID = EmployeeId;
this.Freight = Freight;
this.ShipCity = ShipCity;
this.Verified = Verified;
this.OrderDate = OrderDate;
this.ShipName = ShipName;
this.ShipCountry = ShipCountry;
this.ShippedDate = ShippedDate;
this.ShipAddress = ShipAddress;
}
public static List<OrdersDetails> GetAllRecords()
{
if (order.Count() == 0)
{
int code = 10000;
for (int i = 1; i < 10; i++)
{
order.Add(new OrdersDetails(code + 1, "ALFKI", i + 0, 2.3 * i, false, new DateTime(1991, 05, 15), "Berlin", "Simons bistro", "Denmark", new DateTime(1996, 7, 16), "Kirchgasse 6"));
order.Add(new OrdersDetails(code + 2, "ANATR", i + 2, 3.3 * i, true, new DateTime(1990, 04, 04), "Madrid", "Queen Cozinha", "Brazil", new DateTime(1996, 9, 11), "Avda. Azteca 123"));
order.Add(new OrdersDetails(code + 3, "ANTON", i + 1, 4.3 * i, true, new DateTime(1957, 11, 30), "Cholchester", "Frankenversand", "Germany", new DateTime(1996, 10, 7), "Carrera 52 con Ave. Bolívar #65-98 Llano Largo"));
order.Add(new OrdersDetails(code + 4, "BLONP", i + 3, 5.3 * i, false, new DateTime(1930, 10, 22), "Marseille", "Ernst Handel", "Austria", new DateTime(1996, 12, 30), "Magazinweg 7"));
order.Add(new OrdersDetails(code + 5, "BOLID", i + 4, 6.3 * i, true, new DateTime(1953, 02, 18), "Tsawassen", "Hanari Carnes", "Switzerland", new DateTime(1997, 12, 3), "1029 - 12th Ave. S."));
code += 5;
}
}
return order;
}
public int? OrderID { get; set; }
public string? CustomerID { get; set; }
public int? EmployeeID { get; set; }
public double? Freight { get; set; }
public string? ShipCity { get; set; }
public bool? Verified { get; set; }
public DateTime OrderDate { get; set; }
public string? ShipName { get; set; }
public string? ShipCountry { get; set; }
public DateTime ShippedDate { get; set; }
public string? ShipAddress { get; set; }
}
}The following screenshot represents loading data when the button is clicked and CRUD operations are performed:

A complete sample for binding data and performing CRUD actions via Fetch requests is available on GitHub
Display the loading indicator with local data.
The Data Grid allows a loading indicator to be displayed while local data is being loaded. This feature is useful when there is a delay in loading data from a local source, and it helps indicate that the data is being fetched.
To display the loading indicator with local data, set the showSpinner property to true. This property controls the visibility of the loading indicator.
The following example demonstrates displaying the loading indicator in the grid using the load and created events:
let isDataLoading =true
var grid = new ej.grids.Grid({
allowPaging: true,
created:created,
load:load,
pageSettings: { pageCount: 3,pageSize: 5 },
columns: [
{ field: 'OrderID', headerText: 'Order ID', textAlign: 'Right', width: 120 },
{ field: 'CustomerName', headerText: 'Customer Name', width: 150 },
{ field: 'OrderDate', headerText: 'Order Date', width: 130, format: 'yMd', textAlign: 'Right' },
{ field: 'Freight', headerText: 'Freight', width: 120, format: 'C2', textAlign: 'Right' },
{ field: 'ShippedDate', headerText: 'Shipped Date', width: 140, format: 'yMd', textAlign: 'Right' },
{ field: 'ShipCountry', headerText: 'Ship Country', width: 150 }
],
height: 315
});
grid.appendTo('#Grid');
function load() {
if (isDataLoading) {
grid.showSpinner();
}
}
function created(){
isDataLoading = true;
grid.dataSource = data;
}CRUD Operations using AJAX requests
The Data Grid provides a seamless way to bind data from external sources using AJAX requests, facilitating CRUD (Create, Read, Update, Delete) operations with data retrieved from a server. This feature is particularly valuable for sending data to a server for database updates and asynchronously retrieving data without refreshing the entire web page.
To achieve data binding and perform CRUD actions using Ajax requests in the grid, follow these steps:
Step 1: To create a new ASP.NET Core Web API project named AJAXRequest, follow these steps:
- Open Visual Studio.
- Select “Create a new project”
- Choose ASP.NET Core Web API project template.
- Name the project AJAXRequest.
- Click “Create”
Step 2: Comment out the below line in launchSettings.json:
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
// "launchUrl": "swagger",
"applicationUrl": "https://localhost:xxxx;http://localhost:xxxx",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},Step 3: In the Program.cs file, add the following code:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.UseDefaultFiles();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Grid}/{action=Index}");
app.UseStaticFiles();
app.MapControllers();
app.Run();Step 4: Create a folder named wwwroot in the project root directory. This folder will contain static files served by the web server.
Step 5: Create an index.html file under the wwwroot folder and add the following code::
<!DOCTYPE html>
<html lang="en">
<head>
<title>EJ2 Grid</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Javascript Grid Control">
<meta name="author" content="Syncfusion">
<link href="https://cdn.syncfusion.com/ej2/35.1.37/material3.css" rel="stylesheet" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
<script src="https://cdn.syncfusion.com/ej2/35.1.37/dist/ej2.min.js" type="text/javascript"></script>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type="text/javascript"></script>
</head>
<body>
<div class='col-md-9'>
<div style="padding-bottom: 10px; padding-top:10px">
<button ejs-button id="buttons" cssClass="e-small"></button>
</div>
<div id="container">
<div id="Grid"></div>
</div>
</div>
<script src="js/index.js" type="text/javascript"></script>
</body>
</html>Step 6: Create a js folder under the wwwroot folder, then create an index.js file within the js folder and follow the steps below:
A. To bind data from an external AJAX request, utilize the dataSource property of the grid. AJAX data from the server and provide it to the dataSource property using the onSuccess event of the AJAX request.
B. To perform CRUD actions, leverage the actionBegin event. The default CRUD operations can be canceled by utilizing the cancel argument provided by this event. This enables a dynamic call to the server-side method using AJAX, along with the relevant data received from the actionBegin event, to update server data accordingly.
C. In the AJAX success event, the grid endEdit and deleteRecord methods can be used to handle the addition, editing, and deletion of corresponding data in the grid. However, invoking these methods triggers the actionBegin event once again to save the changes in the grid. To prevent this behavior and maintain control over the execution flow, a flag variable can be employed and managed within the actionComplete and AJAX failure events: The following code snippet demonstrates this approach:
var grid = new ej.grids.Grid({
toolbar: ['Add', 'Edit', 'Delete', 'Update', 'Cancel'],
allowPaging: true,
actionBegin: actionBegin,
actionComplete: actionComplete,
editSettings: { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Normal' },
columns: [
{ field: 'OrderID', headerText: 'Order ID', textAlign: 'Right', width: 120, isPrimaryKey: true, type: 'number' },
{ field: 'CustomerID', width: 140, headerText: 'Customer ID', type: 'string' },
{ field: 'ShipCity', headerText: 'ShipCity', width: 140 },
{ field: 'ShipCountry', headerText: 'ShipCountry', width: 140 }
]
});
grid.appendTo('#Grid');
var button = new ej.buttons.Button({
content: 'Bind data via AJAX',
cssClass: 'e-success'
});
button.appendTo('#buttons');
let flag = false;
document.getElementById('buttons').onclick = function () {
const ajaxRequest = new ej.base.Ajax("https://localhost:****/Grid/Getdata", 'POST'); //Use remote server host instead number ****
ajaxRequest.send();
ajaxRequest.onSuccess = (data) => {
grid.dataSource = JSON.parse(data);
};
};
function actionComplete(e) {
if (e.requestType === 'save' || e.requestType === 'delete') {
flag = false;
}
}
function actionBegin(e) {
if (!flag) {
if (e.requestType == 'save' && (e.action == 'add')) {
var editedData = e.data;
e.cancel = true;
var ajaxRequest = new ej.base.Ajax({
url: 'https://localhost:****/Grid/Insert',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ value: editedData })
}); //Use remote server host instead number ****
ajaxRequest.onSuccess = () => {
flag = true;
grid.endEdit();
};
ajaxRequest.onFailure = () => {
flag = false;
};
ajaxRequest.send();
}
if (e.requestType == 'save' && (e.action == "edit")) {
var editedData = e.data;
e.cancel = true;
var ajaxRequest = new ej.base.Ajax({
url: 'https://localhost:****/Grid/Update',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ value: editedData })
}); //Use remote server host instead number ****
ajaxRequest.onSuccess = () => {
flag = true;
grid.endEdit();
};
ajaxRequest.onFailure = () => {
flag = false;
};
ajaxRequest.send();
}
if (e.requestType == 'delete') {
var editedData = e.data;
e.cancel = true;
var ajaxRequest = new ej.base.Ajax({
url: 'https://localhost:****/Grid/Delete',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ key: editedData[0][grid.getPrimaryKeyFieldNames()[0]] })
});//Use remote server host instead number ****
ajaxRequest.onSuccess = () => {
flag = true;
grid.deleteRecord();
};
ajaxRequest.onFailure = () => {
flag = false;
};
ajaxRequest.send();
}
}
}Step 7: Create a GridController.cs file in the Controllers folder. On the server side, there is a method named GetData within the GridController that provides the data source for the grid. When the button is clicked, a AJAX request is sent to retrieve the data from the server and bind it to the Data Grid component. Additionally, implement server-side logic to perform add, edit, and delete operations.
using AJAXRequest.Models;
using Microsoft.AspNetCore.Mvc;
namespace AJAXRequest.Controllers
{
public class GridController : Controller
{
public ActionResult Getdata()
{
var DataSource = OrdersDetails.GetAllRecords();
return Json(DataSource);
}
//update the record in server side
public ActionResult Update([FromBody] CRUDModel<OrdersDetails> value)
{
var ord = value.value;
OrdersDetails val = OrdersDetails.GetAllRecords().Where(or => or.OrderID == ord.OrderID).FirstOrDefault();
val.OrderID = ord.OrderID;
val.EmployeeID = ord.EmployeeID;
val.CustomerID = ord.CustomerID;
val.Freight = ord.Freight;
val.OrderDate = ord.OrderDate;
val.ShipCity = ord.ShipCity;
val.ShipCountry = ord.ShipCountry;
return Json(value.value);
}
//insert the record
public ActionResult Insert([FromBody] CRUDModel<OrdersDetails> value)
{
OrdersDetails.GetAllRecords().Insert(0, value.value);
return Json(value.value);
}
//Delete the record
public ActionResult Delete(int key)
{
OrdersDetails.GetAllRecords().Remove(OrdersDetails.GetAllRecords().Where(or => or.OrderID == key).FirstOrDefault());
var data = OrdersDetails.GetAllRecords();
return Json(data);
}
}
}
public class CRUDModel<T> where T : class
{
public string action { get; set; }
public string table { get; set; }
public string keyColumn { get; set; }
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; }
}Step 8: Create a model class named OrdersDetails.cs under the Models folder in the server-side project to represent the order data.
namespace AJAXRequest.Models
{
public class OrdersDetails
{
public static List<OrdersDetails> order = new List<OrdersDetails>();
public OrdersDetails()
{
}
public OrdersDetails(
int OrderID, string CustomerId, int EmployeeId, double Freight, bool Verified,
DateTime OrderDate, string ShipCity, string ShipName, string ShipCountry,
DateTime ShippedDate, string ShipAddress)
{
this.OrderID = OrderID;
this.CustomerID = CustomerId;
this.EmployeeID = EmployeeId;
this.Freight = Freight;
this.ShipCity = ShipCity;
this.Verified = Verified;
this.OrderDate = OrderDate;
this.ShipName = ShipName;
this.ShipCountry = ShipCountry;
this.ShippedDate = ShippedDate;
this.ShipAddress = ShipAddress;
}
public static List<OrdersDetails> GetAllRecords()
{
if (order.Count() == 0)
{
int code = 10000;
for (int i = 1; i < 10; i++)
{
order.Add(new OrdersDetails(code + 1, "ALFKI", i + 0, 2.3 * i, false, new DateTime(1991, 05, 15), "Berlin", "Simons bistro", "Denmark", new DateTime(1996, 7, 16), "Kirchgasse 6"));
order.Add(new OrdersDetails(code + 2, "ANATR", i + 2, 3.3 * i, true, new DateTime(1990, 04, 04), "Madrid", "Queen Cozinha", "Brazil", new DateTime(1996, 9, 11), "Avda. Azteca 123"));
order.Add(new OrdersDetails(code + 3, "ANTON", i + 1, 4.3 * i, true, new DateTime(1957, 11, 30), "Cholchester", "Frankenversand", "Germany", new DateTime(1996, 10, 7), "Carrera 52 con Ave. Bolívar #65-98 Llano Largo"));
order.Add(new OrdersDetails(code + 4, "BLONP", i + 3, 5.3 * i, false, new DateTime(1930, 10, 22), "Marseille", "Ernst Handel", "Austria", new DateTime(1996, 12, 30), "Magazinweg 7"));
order.Add(new OrdersDetails(code + 5, "BOLID", i + 4, 6.3 * i, true, new DateTime(1953, 02, 18), "Tsawassen", "Hanari Carnes", "Switzerland", new DateTime(1997, 12, 3), "1029 - 12th Ave. S."));
code += 5;
}
}
return order;
}
public int? OrderID { get; set; }
public string? CustomerID { get; set; }
public int? EmployeeID { get; set; }
public double? Freight { get; set; }
public string? ShipCity { get; set; }
public bool? Verified { get; set; }
public DateTime OrderDate { get; set; }
public string? ShipName { get; set; }
public string? ShipCountry { get; set; }
public DateTime ShippedDate { get; set; }
public string? ShipAddress { get; set; }
}
}The following screenshot represents loading data when the button is clicked and CRUD operations are performed:

A complete sample for binding data and performing CRUD actions via AJAX requests is available on GitHub
Display the loading indicator using AJAX.
The Data Grid allows a loading indicator to be displayed while data is loading through AJAX. This feature is useful when there is a delay in loading data from a remote source, and it helps indicate that the data is being fetched. This is particularly beneficial when working with large datasets or slower internet connections.
To display the loading indicator with local data, set the showSpinner property to true. This property controls the visibility of the loading indicator.
The following example demonstrates displaying the loading indicator in the grid using the load and created events:
let isDataLoading =true
var grid = new ej.grids.Grid({
allowPaging: true,
created:created,
load:load,
pageSettings: { pageCount: 3,pageSize: 5 },
columns: [
{ field: 'OrderID', headerText: 'Order ID', textAlign: 'Right', width: 120 },
{ field: 'CustomerName', headerText: 'Customer Name', width: 150 },
{ field: 'OrderDate', headerText: 'Order Date', width: 130, format: 'yMd', textAlign: 'Right' },
{ field: 'Freight', headerText: 'Freight', width: 120, format: 'C2', textAlign: 'Right' },
{ field: 'ShippedDate', headerText: 'Shipped Date', width: 140, format: 'yMd', textAlign: 'Right' },
{ field: 'ShipCountry', headerText: 'Ship Country', width: 150 }
],
height: 315
});
grid.appendTo('#Grid');
function load() {
if (isDataLoading) {
grid.showSpinner();
isDataLoading = false;
}
}
function created() {
isDataLoading = true;
const ajax = new ej2.base.Ajax(
'https://services.syncfusion.com/angular/production/api/orders',
'GET'
);
ajax.send();
ajax.onSuccess = (data) => {
grid.dataSource = JSON.parse(data);
};
}Managing spinner visibility during data loading
Showing a spinner during data loading in the grid enhances the experience by providing a visual indication of the loading progress. This feature helps to understand that data is being fetched or processed.
To show or hide a spinner during data loading in the grid, use the showSpinner and hideSpinner methods provided by the Data Grid component.
The following example demonstrates showing and hiding the spinner during data loading using external buttons in a grid.
var grid = new ej.grids.Grid({
height: 272,
allowPaging: true,
columns: [
{ field: 'OrderID', headerText: 'Order ID', width: '90', textAlign: 'Right' },
{ field: 'CustomerID', headerText: 'Customer ID', width: '100' },
{ field: 'ProductName', headerText: 'Product Name', width: '110' },
{ field: 'Quantity', headerText: 'Quantity', width: '100' },
],
});
grid.appendTo('#Grid');
var loadButton = new ej.buttons.Button({ cssClass: 'e-outline' }, '#LoadButton');
var showButton = new ej.buttons.Button({ cssClass: 'e-outline' }, '#ShowButton');
var hideButton = new ej.buttons.Button({ cssClass: 'e-outline' }, '#HideButton');
document.getElementById('LoadButton').addEventListener('click', function () {
grid.showSpinner();
setTimeout(() => {
grid.dataSource = data;
grid.hideSpinner();
}, 1000);
});
document.getElementById('ShowButton').addEventListener('click', function () {
grid.showSpinner();
});
document.getElementById('HideButton').addEventListener('click', function () {
grid.hideSpinner();
});<!DOCTYPE html><html lang="en"><head>
<title>EJ2 Grid</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Typescript Grid Control">
<meta name="author" content="Syncfusion">
<link href="index.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/35.1.37/material3.css" rel="stylesheet" />
<script src="https://cdn.syncfusion.com/ej2/35.1.37/dist/ej2.min.js" type="text/javascript"></script>
<script src="es5-datasource.js" type="text/javascript"></script>
</head>
<body>
<div id="container">
<button id="LoadButton" >Load Data</button>
<button style="margin-left: 20px" id="ShowButton" >Show Spinner</button>
<button style="margin-left: 20px" id="HideButton" >Hide Spinner</button>
<div style='margin-top:10px' id="Grid"></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>Immutable mode
Immutable mode in the Data Grid is designed to optimize re-rendering performance by utilizing the object reference and deep compare concept. This mode ensures that when performing grid actions, only the modified or newly added rows are re-rendered, preventing unnecessary re-rendering of unchanged rows.
Enable immutable mode by setting enableImmutableMode to true.
If immutable mode is enabled, when the datasource changes, only newly added rows are regenerated or reused. Consequently, the grid’s queryCellInfo and rowDataBound events trigger only for newly generated rows, not for existing rows.
If immutable mode is not enabled, both newly added rows and existing rows are regenerated or reused when the datasource changes. As a result, the rowDataBound and queryCellInfo events trigger for both newly added and existing rows.
This feature uses the primary key value for data comparison. Therefore, the isPrimaryKey column must be provided.
The following example demonstrates enabling immutable mode in the grid. When add, delete, or update actions are performed, existing rows are not regenerated or reused, ensuring efficient rendering of only the modified or newly added rows:
var grid = new ej.grids.Grid({
dataSource: data,
height: 350,
allowPaging: true,
enableHover: false,
enableImmutableMode: true,
pageSettings: { pageSize: 50 },
selectionSettings: { type: 'Multiple' },
queryCellInfo: function (args) {
if ( args.column.field === 'ShipName' && args.data.ShipName === 'Gems Chevalier') {
args.cell.style.backgroundColor = 'rgb(210, 226, 129)';
}
},
rowDataBound: function (args) {
args.row.style.backgroundColor = args.data.isNewlyAdded ? '' : 'rgb(208, 255, 255)';
},
columns: [
{ field: 'OrderID', headerText: 'Order ID', isPrimaryKey: true, width: '120', textAlign: 'Right' },
{ field: 'CustomerID', headerText: 'Customer ID', width: '120' },
{ field: 'Freight', headerText: 'Freight', width: '120' },
{ field: 'ShipName', headerText: 'Ship Name', width: '120' },
],
});
grid.appendTo('#Grid');
var message = document.getElementById('message');
message.innerHTML = `Initial rows rendered: ${data.length}`;
document.getElementById('addtop').addEventListener('click', function () {
grid.getAllDataRows().forEach(row => {
row.style.backgroundColor = 'rgb(208, 255, 255)';
});
var count = 0;
if (count < 1) {
var newRowData = [];
var addedRecords = {
OrderID: generateOrderId(),
CustomerID: generateCustomerId(),
ShipCity: generateShipCity(),
Freight: generateFreight(),
ShipName: generateShipName(),
isNewlyAdded: true,
};
newRowData.push(addedRecords);
grid.dataSource = [...newRowData, ...grid.dataSource];
count++;
message.innerHTML = count + ' rows rendered after performing the add action';
}
});
document.getElementById('delete').addEventListener('click', function () {
var count = 0;
if (count < 1 && data.length > 0) {
grid.dataSource = grid.dataSource.slice(1);
count++;
message.innerHTML = count + ' rows deleted after performing delete action';
}
});
document.getElementById('update').addEventListener('click', function () {
var count = 0;
var newRowData = grid.dataSource.map(function (row) {
if (row.ShipName === 'Bueno Foods') {
count++;
return { ...row, ShipName: 'Gems Chevalier' };
} else {
return row;
}
});
grid.dataSource = newRowData;
message.innerHTML = count + ' rows updated after performing update action';
});
function generateOrderId() {
return Math.floor(10000 + Math.random() * 90000);
}
function generateCustomerId() {
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var result = '';
for (var i = 0; i < 5; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
}
function generateShipCity() {
var cities = ['London', 'Paris', 'New York', 'Tokyo', 'Berlin'];
return cities[Math.floor(Math.random() * cities.length)];
}
function generateFreight() {
var randomValue = Math.random() * 100;
return parseFloat(randomValue.toFixed(2));
}
function generateShipName() {
var names = ['Que Delícia', 'Bueno Foods', 'Island Trading', 'Laughing Bacchus Winecellars'];
return names[Math.floor(Math.random() * names.length)];
}<!DOCTYPE html><html lang="en"><head>
<title>EJ2 Grid</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Typescript Grid Control">
<meta name="author" content="Syncfusion">
<link href="index.css" rel="stylesheet">
<link href="https://cdn.syncfusion.com/ej2/35.1.37/material3.css" rel="stylesheet" />
<script src="https://cdn.syncfusion.com/ej2/35.1.37/dist/ej2.min.js" type="text/javascript"></script>
<script src="es5-datasource.js" type="text/javascript"></script>
<style>
.message{
color:red;
text-align: center;
}
</style>
</head>
<body>
<div id="container">
<button id="addtop" class="e-control e-btn e-lib e-info">Add rows Data</button>
<button style="margin-left: 20px" id="delete" class="e-control e-btn e-lib e-info">Delete rows</button>
<button style="margin-left: 20px" id="update" class="e-control e-btn e-lib e-info">Update Freight Data</button>
<div id="message" class="message"> </div>
<div id="Grid"></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>Immutable mode constraints
Immutable mode updates only the rows whose data has changed to improve rendering performance. As a result, features that rely on complex layouts, advanced rendering scenarios, data processing operations, or interactive grid behaviors may not function as expected.ng