Local data in EJ2 JavaScript Grid control

29 Jun 202424 minutes to read

The Syncfusion Grid offers a straight forward way to bind local data, such as arrays or JSON objects, to the grid control. This feature allows you to display and manipulate data within the grid without the need for external server calls, making it particularly useful for scenarios where you’re working with static or locally stored data.

To achieve this, you can assign a JavaScript object array to the dataSource property. Additionally, you have an option to provide the local data source using an instance of the DataManager.

The following example demonstrates how to utilize the local data binding feature in the EJ2 JavaScript Grid control:

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/26.2.4/ej2-base/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-grids/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-buttons/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-popups/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-richtexteditor/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-navigations/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-dropdowns/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-lists/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-inputs/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-calendars/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-notifications/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-splitbuttons/styles/bootstrap5.css" rel="stylesheet">
<script src="https://cdn.syncfusion.com/ej2/26.2.4/dist/ej2.min.js" type="text/javascript"></script>
<script src="es5-datasource.js" type="text/javascript"></script>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.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 file

The Syncfusion Grid control allows you to import data from Excel files into your web application for display and manipulation within the grid. This feature streamlines the process of transferring Excel data to a web-based environment. This can be achieved by using Uploader control change event.

To bind data from an Excel file to a Syncfusion Grid control, including the xlsx library via a script tag in an HTML page

<script type="text/javascript" src="https://unpkg.com/xlsx@0.15.1/dist/xlsx.full.min.js"></script>

To import excel data in to grid, you can follow these steps:

  1. Import excel file using Uploader control.
  2. Parse the excel file data using XLSX library.
  3. Bind the JSON to the grid control.

The following example demonstrates how to import 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/26.2.4/ej2-base/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-grids/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-buttons/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-popups/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-richtexteditor/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-navigations/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-dropdowns/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-lists/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-inputs/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-calendars/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-notifications/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-splitbuttons/styles/bootstrap5.css" rel="stylesheet">
<script src="https://cdn.syncfusion.com/ej2/26.2.4/dist/ej2.min.js" type="text/javascript"></script>
<script type="text/javascript" src="https://unpkg.com/xlsx@0.15.1/dist/xlsx.full.min.js"></script>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></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>

Managing spinner visibility during data loading

Showing a spinner during data loading in the Syncfusion EJ2 JavaScript 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, you can utilize the showSpinner and hideSpinner methods provided by the Grid control.

The following example demonstrates how to show and hide 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/26.2.4/ej2-base/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-grids/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-buttons/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-popups/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-richtexteditor/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-navigations/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-dropdowns/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-lists/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-inputs/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-calendars/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-notifications/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-splitbuttons/styles/bootstrap5.css" rel="stylesheet">
<script src="https://cdn.syncfusion.com/ej2/26.2.4/dist/ej2.min.js" type="text/javascript"></script>
<script src="es5-datasource.js" type="text/javascript"></script>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.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 Syncfusion 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.

To enable this feature, you need to set the enableImmutableMode property as 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. So, you need to provide the isPrimaryKey column.

The following example demonstrates how to enable immutable mode in an EJ2 JavaScript control. 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/26.2.4/ej2-base/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-grids/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-buttons/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-popups/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-richtexteditor/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-navigations/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-dropdowns/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-lists/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-inputs/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-calendars/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-notifications/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/26.2.4/ej2-splitbuttons/styles/bootstrap5.css" rel="stylesheet">
<script src="https://cdn.syncfusion.com/ej2/26.2.4/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>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</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>

Limitations

The following features are not supported in the immutable mode:

  • Frozen rows and columns
  • Grouping
  • Row Template
  • Detail Template
  • Hierarchy Grid
  • Scrolling
  • Virtual scroll
  • Infinite scroll
  • Column reorder
  • Rows, column spanning
  • PDF export, Excel export, Print
  • Column Resize
  • Drag and drop
  • Column template
  • Column chooser
  • Clipboard
  • AutoFit
  • Filtering