Search results

How To

Refresh the data source

You can add/delete the data source records through an external button. To reflect the data source changes in the grid, invoke the refresh method.

To refresh the data source:

Step 1:

Add/delete the data source record by using the following code.

    grid.dataSource.unshift(data); // add a new record.

    grid.dataSource.splice(selectedRow, 1); // delete a record.

Step 2:

Refresh the grid after the data source change by using the refresh method.

    grid.refresh(); // refresh the Grid.
razor
refresh-datasource.cs
@Html.EJS().Button("add").Content("Add").IsPrimary(true).Render()

@Html.EJS().Button("delete").Content("Delete").IsPrimary(true).Render()

@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).Columns(col =>
{
   col.Field("OrderID").HeaderText("Order ID").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("CustomerID").HeaderText("Customer Name").Width("150").Add();
   col.Field("OrderDate").HeaderText("Order Date").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Format("yMd").Add();
   col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("ShipCountry").HeaderText("Ship Country").Width("120").Add();

}).Render()

<script>
    document.getElementById('add').onclick = () => {
        var grid = document.getElementById("Grid").ej2_instances[0];
        var data = { OrderID: 10247, CustomerID: "ASDFG", Freight: 40.4, OrderDate: new Date(8367642e5), ShipCountry: "Austria" };
        grid.dataSource.unshift(data); // add new record.
        grid.refresh(); // refresh the Grid.
    };

    document.getElementById('delete').onclick = () => {
        var grid = document.getElementById("Grid").ej2_instances[0];
        if (grid.getSelectedRowIndexes().length) {
            var selectedRow = grid.getSelectedRowIndexes()[0];
            grid.dataSource.splice(selectedRow, 1); // delete the selected record.
        } else {
            alert("No records selected for delete operation");
        }
        grid.refresh(); // refresh the Grid.
    };

</script>
public IActionResult Index()
{
    ViewBag.DataSource = OrderDetails.GetAllRecords();
    return View();
}

Enable/Disable Grid and its actions

You can enable/disable the Grid and its actions by applying/removing corresponding CSS styles.

To enable/disable the grid and its actions, follow the given steps:

Step 1:

Create CSS class with custom style to override the default style of Grid.

        .disablegrid {
            pointer-events: none;
            opacity: 0.4;
        }
        .wrapper {
            cursor: not-allowed;
        }

Step 2:

Add/Remove the custom CSS class to the Grid in the click event handler of Button.

    <script>
        document.getElementById('element').onclick = function () {
            var gridInst = document.getElementById("Grid").ej2_instances[0];
            if (gridInst.element.classList.contains('disablegrid')) {
                gridInst.element.classList.remove('disablegrid');
                document.getElementById("GridParent").classList.remove('wrapper');
            }
            else {
                gridInst.element.classList.add('disablegrid');
                document.getElementById("GridParent").classList.add('wrapper');
            }
        }
    </script>

In the below demo, the button click will enable/disable the Grid and its actions.

razor
disablegrid.cs
@Html.EJS().Button("element").Content("Enable/Disable Grid").Render()


@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).Columns(col =>
{
   col.Field("OrderID").HeaderText("Order ID").IsPrimaryKey(true).Width("120").Add();
   col.Field("CustomerID").HeaderText("Customer Name").Width("150").Add();
   col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").Add();
   col.Field("ShipCountry").HeaderText("Ship Country").Width("150").Add();

}).AllowPaging().EditSettings(edit => { edit.AllowAdding(true).AllowEditing(true).AllowDeleting(true).Mode(Syncfusion.EJ2.Grids.EditMode.Normal); }).Toolbar(new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" }).Render()


<style>
    .disablegrid {
        pointer-events: none;
        opacity: 0.4;
    }

    .wrapper {
        cursor: not-allowed;
    }
</style>

<script>
    document.getElementById('element').onclick = function () {
        var gridInst = document.getElementById("Grid").ej2_instances[0];
        if (gridInst.element.classList.contains('disablegrid')) {
            gridInst.element.classList.remove('disablegrid');
            document.getElementById("GridParent").classList.remove('wrapper');
        }
        else {
            gridInst.element.classList.add('disablegrid');
            document.getElementById("GridParent").classList.add('wrapper');
        }
    }
</script>
public IActionResult Index()
{
    var Order = OrderDetails.GetAllRecords();
    ViewBag.DataSource = Order;
    return View();
}

By default, the expanded child grids will be printed from the current page alone. You can print the expanded child grids from other pages by using the load and actionBegin event.

In the following example, we have printed expanded child grids form other pages.

razor
hierarchyprint.cs
@{
   var SecondChildGrid = new Syncfusion.EJ2.Grids.Grid() { DataSource = (IEnumerable<object>)ViewBag.CustomerDataSource,
       QueryString = "CustomerID",
       Columns = new List<Syncfusion.EJ2.Grids.GridColumn>
       {
         new Syncfusion.EJ2.Grids.GridColumn(){ Field="CustomerID", HeaderText="Customer ID", Width="90", TextAlign=Syncfusion.EJ2.Grids.TextAlign.Right },
         new Syncfusion.EJ2.Grids.GridColumn(){ Field="ShipCountry", HeaderText="Ship Country", Width="90" },
        }
   };
   var ChildGrid = new Syncfusion.EJ2.Grids.Grid() { DataSource = (IEnumerable<object>)ViewBag.DataSource,
          QueryString = "EmployeeID",
          Columns = new List<Syncfusion.EJ2.Grids.GridColumn>
          {
            new Syncfusion.EJ2.Grids.GridColumn(){ Field="OrderID", HeaderText="Order ID", Width="120" },
            new Syncfusion.EJ2.Grids.GridColumn(){ Field="Freight", HeaderText="Freight", Width="120", Format="C2", TextAlign=Syncfusion.EJ2.Grids.TextAlign.Right },
            new Syncfusion.EJ2.Grids.GridColumn(){ Field="ShipName", HeaderText="Ship Name", Width="150" },
            new Syncfusion.EJ2.Grids.GridColumn(){ Field="ShipCity", HeaderText="Ship City", Width="120" },
          },
          ChildGrid = SecondChildGrid
      };
 }
                
@Html.EJS().Grid("HierarchyPrint").DataSource((IEnumerable<object>)ViewBag.EmpDataSource).HierarchyPrintMode(Syncfusion.EJ2.Grids.HierarchyGridPrintMode.Expanded).Columns(col =>
{
   col.Field("EmployeeID").HeaderText("Employee ID").Width("125").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("FirstName").HeaderText("Name").Width("125").Add();
   col.Field("Title").HeaderText("Title").Width("180").Add();
   col.Field("City").HeaderText("City").Width("135").Add();

}).AllowSorting().AllowPaging().PageSettings(page => page.PageSize(5)).Toolbar(new List<string>() { "Print"}).ChildGrid(ChildGrid).ActionBegin("actionBegin").Load("load").Render()

                
<script>

    var expandedChildGrid = {};

    function actionBegin(args) {
        if (args.requestType === 'paging') {
           expandedChildGrid = ej.base.extend({}, expandedChildGrid, getExpandedState(this, 'Expanded', args.previousPage));
        }
    }

    function load() {
        this.on(ej.grids.printGridInit, printInit, this);
    }

    function printInit(gridModel) {
        gridModel.printgrid.expandedRows = ej.base.extend({}, expandedChildGrid, gridModel.expandedRows);
    }

    function getExpandedState(gObj, hierarchyPrintMode, currentPage) {
         var obj = {};
         var rows = gObj.getRowsObject();
         for (var i = 0; i < rows.length; i++) {
             var row = rows[i];
             if (row.isExpand && !row.isDetailRow) {
                var index = gObj.allowPaging ? row.index + (currentPage * gObj.pageSettings.pageSize) - gObj.pageSettings.pageSize : row.index;
                obj[index] = {};
                obj[index].isExpand = true;
                obj[index].gridModel = ej.grids.getPrintGridModel(row.childGrid, hierarchyPrintMode);
             }
         }
         return obj;
     }
 </script>
public IActionResult Index()
{
    ViewBag.DataSource =  OrdersDetails.GetAllRecords();;
    ViewBag.EmpDataSource = EmployeeView.GetAllRecords();
    ViewBag.CustomerDataSource = Customer.GetAllRecords();
    return View();
}

Columns

Change column header text dynamically

You can change the column HeaderText dynamically through an external button.

Follow the given steps to change the header text dynamically:

Step 1:

Get the column object corresponding to the field name by using the getColumnByField method. Then, change the header text value.

var column = grid.getColumnByField("ShipCity"); // Get column object.
column.headerText = 'Changed Text';

Step 2:

To reflect the changes in the grid header, invoke the refreshHeader method.

grid.refreshHeader();
razor
column-header-text.cs
@Html.EJS().Button("change-text").Content("Change Header Text").IsPrimary(true).Render()

@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).Columns(col =>
{
   col.Field("OrderID").HeaderText("Order ID").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("CustomerID").HeaderText("Customer Name").Width("150").Add();
   col.Field("OrderDate").HeaderText("Order Date").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Format("yMd").Add();
   col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("ShipCountry").HeaderText("Ship Country").Width("120").Add();

}).AllowPaging().Render()

<script>
    document.getElementById('change-text').addEventListener('click', () => { // changing the header text for ShipCity column.
        var grid = document.getElementById("Grid").ej2_instances[0];
        var column = grid.getColumnByField("Freight"); // get the JSON object of the column corresponding to the field name.
        column.headerText = "Changed Text"; // assign a new header text to the column.
        grid.refreshHeader();
    });
</script>
public IActionResult Index()
{
    ViewBag.DataSource = OrderDetails.GetAllRecords();
    return View();
}

Customize column styles

You can customise the appearance of the header and content of a particular column using the customAttributes property.

To customize the grid column, follow the given steps:

Step 1:

Create a CSS class with custom style to override the default style for rowcell and headercell.

.e-grid .e-rowcell.customcss{
    background-color: #ecedee;
    color: 'red';
    font-family: 'Bell MT';
    font-size: 20px;
}

.e-grid .e-headercell.customcss{
    background-color: #2382c3;
    color: white;
    font-family: 'Bell MT';
    font-size: 20px;
}

Step 2:

Add the custom CSS class to the specified column by using the customAttributes property.

<e-grid-column field="Freight" headerText="Freight" width="150"  customAttributes=@(new { @class="customcss" } )></e-grid-column>
razor
custom-column-style.cs
@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).Columns(col =>
{
    col.Field("OrderID").HeaderText("Order ID").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
    col.Field("CustomerID").HeaderText("Customer Name").Width("150").Add();
    col.Field("OrderDate").HeaderText("Order Date").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Format("yMd").Add();
    col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).CustomAttributes(new { @class = "customcss" }).Add();
    col.Field("ShipCountry").HeaderText("Ship Country").Width("120").Add();
}).AllowPaging().Render()

<style>

    .e-grid .e-rowcell.customcss {
        background-color: #ecedee;
        color: red;
        font-family: 'Bell MT';
        font-size: 20px;
    }

    .e-grid .e-headercell.customcss {
        background-color: #2382c3;
        color: white;
        font-family: 'Bell MT';
        font-size: 20px;
    }

</style>
public IActionResult Index()
{
    ViewBag.DataSource = OrderDetails.GetAllRecords();
    return View();
}

Display custom ToolTip for columns in Grid

To display custom ToolTip (EJ2 Tooltip), use the QueryCellInfo event.

Render the ToolTip component for the grid cells by using the following code in the QueryCellInfo event.

function tooltip (args) {
    var tooltip = new ej.popups.Tooltip({
        content: args.data[args.column.field].toString();
    }, args.cell);
}
razor
custom-tooltip.cs
@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).Columns(col =>
{
   col.Field("OrderID").HeaderText("Order ID").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("CustomerID").HeaderText("Customer Name").Width("150").Add();
   col.Field("OrderDate").HeaderText("Order Date").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Format("yMd").Add();
   col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("ShipCountry").HeaderText("Ship Country").Width("120").Add();

}).QueryCellInfo("tooltip").Render()

<script>
    function tooltip(args) { // event triggers on every cell render.
        new ej.popups.Tooltip({
            content: args.data[args.column.field].toString() // add Essential JS2 tooltip for every cell.
        }, args.cell);
    }
</script>
public IActionResult Index()
{
    ViewBag.DataSource = OrderDetails.GetAllRecords();
    return View();
}

Render other components in a column

You can render any component in a grid column using the Template property.

To render other components in the grid, ensure the following steps:

Step 1:

Initialize the column template for your custom component.

template:`<div>
            <select class="e-control e-dropdownlist">
                <option value="1" selected="selected">Order Placed</option>
                <option value="2">Processing</option>
                <option value="3">Delivered</option>
            </select>
        </div>`

Step 2:

Using the QueryCellInfo event, you can render the DropDown component with the following code.

    function dropdown(args) {
        let ele=args.cell.querySelector('select');
        let drop = new ej.dropdowns.DropDownList({popupHeight: 150, popupWidth: 150});
        drop.appendTo(ele);
    }
razor
@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).Columns(col =>
{
   col.HeaderText("Order Status").Width("200").Template("#dropdown").Add();
   col.Field("OrderID").HeaderText("Order ID").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("CustomerID").HeaderText("Customer Name").Width("150").Add();
   col.Field("OrderDate").HeaderText("Order Date").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Format("yMd").Add();
   col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("ShipCountry").HeaderText("Ship Country").Width("120").Add();

}).QueryCellInfo("dropdown").Render()

<div id='dropdown'>
    <select class="e-control e-dropdownlist">
        <option value="1" selected="selected">Order Placed</option>
        <option value="2">Processing</option>
        <option value="3">Delivered</option>
    </select>
</div>

<script>
    function dropdown(args) {
        var ele = args.cell.querySelector('select');
        var drop = new ej.dropdowns.DropDownList({ popupHeight: 150, popupWidth: 150 });
        drop.appendTo(ele);
    }
</script>

Change the orientation of the header text

You can change the orientation of the header text by using the CustomAttributes property.

Ensure the following steps:

Step 1:

Create a CSS class with orientation style for the grid header cell.

.orientationcss .e-headercelldiv {
    transform: rotate(90deg);
}

Step 2:

Add the custom CSS class to a particular column by using the CustomAttributes property.

    <e-grid-column field="ShipCity" headerText="Ship City" width="150" customAttributes=new { class='orientationcss' }"></e-grid-column>

Step 3:

Resize the header cell height by using the following code.

function setHeaderHeight(args) {
    var textWidth = document.querySelector(".orientationcss > div").scrollWidth;//Obtain the width of the headerText content.
    var headerCell = document.querySelectorAll(".e-headercell");
    for(var i = 0; i < headerCell.length; i++) {
        headerCell.item(i).style.height = textWidth + 'px'; //Assign the obtained textWidth as the height of the headerCell.
    }
}
razor
orientation.cs
@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).Columns(col =>
{
   col.Field("OrderID").HeaderText("Order ID").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("CustomerID").HeaderText("Customer Name").Width("150").Add();
   col.Field("OrderDate").HeaderText("Order Date").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Format("yMd").Add();
   col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("ShipCountry").HeaderText("Ship Country").Width("120").CustomAttributes(new { @class="orientationcss" }).Add();

}).Created("setHeaderHeight").Render()

<style>
    .orientationcss .e-headercelldiv {
        transform: rotate(90deg);
    }
</style>

<script>
    function setHeaderHeight(args) {
        var textWidth = document.querySelector(".orientationcss > div").scrollWidth; // obtain the width of the headerText content.
        var headerCell = document.querySelectorAll(".e-headercell");
        for (var i = 0; i < headerCell.length; i++) {
            headerCell.item(i).style.height = textWidth + 'px'; // assign the obtained textWidth as the height of the headerCell.
        }
    }
</script>
public IActionResult Index()
{
    ViewBag.DataSource = OrderDetails.GetAllRecords();
    return View();
}

Customize the icon for column menu

You can customize the column menu icon by overriding the default grid class .e-icons.e-columnmenu with a custom property content as mentioned below,

.e-grid .e-columnheader .e-icons.e-columnmenu::before {
              content: "\e941";
      }

In the below sample, grid is rendered with a customized column menu icon.

razor
column-icon.cs
@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).ShowColumnMenu(true).Columns(col =>
{
  col.Field("OrderID").HeaderText("Order ID").Width("120").Add();
  col.Field("CustomerID").HeaderText("Customer Name").Width("150").Add();
  col.Field("OrderDate").HeaderText("Order Date").Width("130").Format("yMd").Add();
  col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").Add();
  col.Field("ShipCountry").HeaderText("Ship Country").Width("120").Add();

 }).Render()

<style>
    .e-grid .e-columnheader .e-icons.e-columnmenu::before {
        content: "\e969";
    }
</style>
public IActionResult Index()
{
    ViewBag.DataSource = OrderDetails.GetAllRecords();
    return View();
}

Editing

Perform CRUD operation using anti-forgery token

Anti-forgery token is used between the client and server to prevent cross-site request forgery (CSRF) attack. For more information on preventing CSRF attack, please refer to the link.

While performing grid save operation, you can send anti-forgery token along with the save request using the below custom adaptor.

This custom adaptor will read the anti-forgery token from the hidden element and send it along with the request. Also content type is set to application/x-www-form-urlencoded; charset=UTF-8 since the ValidateAntiForgeryToken will look for the token in the form encoded data.

<script>

    window.customAdaptor = new ej.data.UrlAdaptor();

    customAdaptor = ej.base.extend(customAdaptor, {

        processResponse: function (data, ds, query, xhr, request, changes) {
            request.data = JSON.stringify(data);
            return ej.data.UrlAdaptor.prototype.processResponse.call(this,data, ds, query, xhr, request, changes);
        },
        insert: function (dm, data, tableName) {
            return {
                url: dm.dataSource.insertUrl || dm.dataSource.crudUrl || dm.dataSource.url,
                data: $.param({
                    //Added the anti-forgery token.
                    __RequestVerificationToken: document.getElementsByName("__RequestVerificationToken")[0].value,
                    value: data,
                    table: tableName,
                    action: 'insert'
                }),
                contentType: 'application/x-www-form-urlencoded; charset=UTF-8'
            }
        },
        update: function (dm, keyField, value, tableName) {
            return {
                url: dm.dataSource.updateUrl || dm.dataSource.crudUrl || dm.dataSource.url,
                data: $.param({
                    //Added the anti-forgery token.
                    __RequestVerificationToken: document.getElementsByName("__RequestVerificationToken")[0].value,
                    value: value,
                    table: tableName,
                    action: 'insert'
                }),
                contentType: 'application/x-www-form-urlencoded; charset=UTF-8'
            };
        },
    });
</script>

Now assign the custom adaptor to the grid as follows.

<script>
    function load(args) {
        this.dataSource.adaptor = customAdaptor;
    }
</script>
razor
anti-forgery-token.cs
@Html.EJS().Grid("RemoteSaveAdaptor").DataSource(dataManager => { dataManager.Json(ViewBag.dataSource.ToArray()).InsertUrl("/Home/Insert").RemoveUrl("/Home/Delete").UpdateUrl("/Home/Update").Adaptor("RemoteSaveAdaptor");

}).EditSettings(e => { e.AllowAdding(true).AllowEditing(true).AllowDeleting(true); }).Columns(col =>
{
    col.Field("OrderID").HeaderText("Order ID").Width("120").IsPrimaryKey(true).TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
    col.Field("CustomerID").HeaderText("Customer ID").Width("150").Add();
    col.Field("Freight").HeaderText("Freight").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Format("C2").Add();
    col.Field("OrderDate").HeaderText("Order Date").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Format("yMd").Add();

}).Toolbar(new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" }).Render()

<script type="text/javascript">
    window.customAdaptor = new ej.data.RemoteSaveAdaptor();

    customAdaptor = ej.base.extend(customAdaptor, {
        insert(dm, data, tableName) {
            this.updateType = 'add';
            return {
                url: dm.dataSource.insertUrl || dm.dataSource.crudUrl || dm.dataSource.url,
                data: $.param({
                    //Added the anti-forgery token.
                    __RequestVerificationToken: document.getElementsByName("__RequestVerificationToken")[0].value,
                    value: data,
                    table: tableName,
                    action: 'insert'
                }),
                contentType: 'application/x-www-form-urlencoded; charset=UTF-8'
            };
        },
        update(dm, keyField, value, tableName) {
            debugger;
            this.updateType = 'update';
            this.updateKey = keyField;
            return {
                type: 'POST',
                url: dm.dataSource.updateUrl || dm.dataSource.crudUrl || dm.dataSource.url,
                data: $.param({
                    //Added the anti-forgery token.
                    __RequestVerificationToken: document.getElementsByName("__RequestVerificationToken")[0].value,
                    value: value,
                    action: 'update',
                    keyColumn: keyField,
                    key: value[keyField],
                    table: tableName
                }),
                contentType: 'application/x-www-form-urlencoded; charset=UTF-8'
            };
        },
        remove(dm, keyField, value, tableName) {
            ej.data.JsonAdaptor.prototype.remove(dm, keyField, value);
            return {
                type: 'POST',
                url: dm.dataSource.removeUrl || dm.dataSource.crudUrl || dm.dataSource.url,
                data: $.param({
                    //Added the anti-forgery token.
                    __RequestVerificationToken: document.getElementsByName("__RequestVerificationToken")[0].value,
                    key: value,
                    keyColumn: keyField,
                    table: tableName,
                    action: 'remove'

                }),
                contentType: 'application/x-www-form-urlencoded; charset=UTF-8'
            };
        }

    });

    function load(args) {
        this.dataSource.adaptor = customAdaptor;
    }
</script>
public class HomeController : Controller
{
    public static List<Orders> order = new List<Orders>();
    
    public ActionResult Index()
    {
        if (order.Count == 0)
            BindDataSource();
        ViewBag.data = order.ToArray();
        return View();
    }

    public void BindDataSource()
    {
        int code = 10000;
        for (int i = 1; i < 10; i++)
        {
            order.Add(new Orders(code + 1, "VINET", i + 0, 2.3 * i, new DateTime(1991, 05, 15), "Berlin"));
            order.Add(new Orders(code + 2, "ANATR", i + 2, 3.3 * i, new DateTime(1990, 04, 04), "Madrid"));
            order.Add(new Orders(code + 3, "ANTON", i + 1, 4.3 * i, new DateTime(1957, 11, 30), "Cholchester"));
            order.Add(new Orders(code + 4, "BLONP", i + 3, 5.3 * i, new DateTime(1930, 10, 22), "Marseille"));
            order.Add(new Orders(code + 5, "BOLID", i + 4, 6.3 * i, new DateTime(1953, 02, 18), "Tsawassen"));
            code += 5;
        }
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Update(Orders value, string action)
    {
        var data = order.Where(or => or.OrderID == value.OrderID).FirstOrDefault();
        if (data != null)
        {
            data.OrderID = value.OrderID;
            data.CustomerID = value.CustomerID;
            data.EmployeeID = value.EmployeeID;
            data.Freight = value.Freight;
            data.OrderDate = value.OrderDate;
            data.ShipCity = value.ShipCity;
        }
        return Json(value);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Insert(Orders value, string action)
    {
        order.Insert(0, value);
        return Json(value);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public void Remove(int key)
    {
        var data = order.Where(or => or.OrderID == key).FirstOrDefault();
        if (data != null)
        {
            order.Remove(data);
        }
    }

    public class Orders
    {
        public Orders()
        {

        }
        public Orders(long OrderId, string CustomerId, int EmployeeId, double Freight, DateTime OrderDate, string ShipCity)
        {
            this.OrderID = OrderId;
            this.CustomerID = CustomerId;
            this.EmployeeID = EmployeeId;
            this.Freight = Freight;
            this.OrderDate = OrderDate;
            this.ShipCity = ShipCity;
        }
        public long OrderID { get; set; }
        public string CustomerID { get; set; }
        public int EmployeeID { get; set; }
        public double Freight { get; set; }
        public DateTime OrderDate { get; set; }
        public string ShipCity { get; set; }
    }
}

You can find the full sample at our GitHub repository.

Editing with template column

You can edit the template column value by defining the Field for that particular column.

In the below demo, the ShipCountry column is rendered with the template.

razor
edit-temp.cs
@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).Columns(col =>
{
   col.Field("OrderID").HeaderText("Order ID").IsPrimaryKey(true).Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("CustomerID").HeaderText("Customer Name").Width("150").Add();
   col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("ShipName").HeaderText("Ship Name").Width("150").Add();
   col.Field("ShipCountry").HeaderText("Ship Country").Width("150").Template("#template").EditType("dropdownedit").Add();

}).AllowPaging().EditSettings(edit => { edit.AllowAdding(true).AllowEditing(true).AllowDeleting(true).Mode(Syncfusion.EJ2.Grids.EditMode.Normal); }).Toolbar(new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" }).Render()

<script id="template" type="text/x-template">
    <a href="#">${ShipCountry}</a>
</script>
public IActionResult Index()
{
    ViewBag.DataSource = OrderDetails.GetAllRecords();
    return View();
}

Customize the Edit Dialog

You can customize the appearance of the edit dialog in the ActionComplete event based on requestType as beginEdit or add.

In the below example, we have changed the dialog’s header text for editing and adding records.

razor
dialog.cs
@using Syncfusion.EJ2

@section ControlsSection{
    <div class="control-section">
        @Html.EJS().Grid("DialogTemplateEdit").DataSource((IEnumerable<object>)ViewBag.dataSource).ActionComplete("actionComplete").Columns(col =>
   {
       col.Field("OrderID").HeaderText("Order ID").IsPrimaryKey(true).Width("120").ValidationRules(new { required = true }).TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
       col.Field("CustomerID").HeaderText("Customer Name").Width("150").ValidationRules(new { required = true, minLength = 3 }).Add();
       col.Field("ShipCountry").HeaderText("Ship Country").EditType("dropdownedit").Width("150").Add();
   }).AllowPaging().PageSettings(page => page.PageCount(2)).EditSettings(edit => { edit.AllowAdding(true).AllowEditing(true).AllowDeleting(true).Mode(Syncfusion.EJ2.Grids.EditMode.Dialog); }).Toolbar(new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" }).Render()
    </div>
   
    <script>
        function actionComplete(args) {
            if ((args.requestType === 'beginEdit' || args.requestType === 'add')) {
                let dialog: Dialog = args.dialog;
                dialog.height = 400;
                // change the header of the dialog
                dialog.header = args.requestType === 'beginEdit' ? 'Record of ' + args.rowData['CustomerID'] : 'New Customer';
            }
        }
    </script>
}
public IActionResult Index()
{
    var Order = OrderDetails.GetAllRecords();
    ViewBag.DataSource = Order;
    return View();
}

Show or Hide columns in Dialog editing

You can show hidden columns or hide visible column’s editor in the dialog while editing the grid record using actionBegin and actionComplete events.

In the actionBegin event, based on requestType as beginEdit or add. We can show or hide the editor by using column.visible property.

In the actionComplete event, based on requestType as save. We can reset the properties back to the column state.

In the below example, we have rendered the grid columns CustomerID as hidden column and ShipCountry as visible column. In the edit mode, we have changed the CustomerID column to visible state and ShipCountry column to hidden state.

razor
dialog.cs
@using Syncfusion.EJ2

@Html.EJS().Grid("DialogTemplateEdit").DataSource((IEnumerable<object>)ViewBag.DataSource).ActionBegin("actionBegin").ActionComplete("actionComplete").Columns(col =>
{
   col.Field("OrderID").HeaderText("Order ID").IsPrimaryKey(true).Width("120").ValidationRules(new { required = true }).TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("CustomerID").HeaderText("Customer Name").Width("150").Visible(false).Add();
   col.Field("Freight").HeaderText("Freight").EditType("numericedit").Format("C2").Width("150").Add();
   col.Field("ShipCountry").HeaderText("Ship Country").EditType("dropdownedit").Width("150").Add();

}).AllowPaging().PageSettings(page => page.PageCount(2)).EditSettings(edit => { edit.AllowAdding(true).AllowEditing(true).AllowDeleting(true).Mode(Syncfusion.EJ2.Grids.EditMode.Dialog); }).Toolbar(new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" }).Render()

<script>
    function actionBegin(args) {
        if ((args.requestType === 'beginEdit' || args.requestType === 'add')) {
            for (var i = 0; i < this.columns.length; i++) {
               if (this.columns[i].field == "CustomerID") {
                   this.columns[i].visible = true;
               }
               else if (this.columns[i].field == "ShipCountry") {
                   this.columns[i].visible = false;
               }
            }
        }
    }

    function actionComplete(args) {
        if (args.requestType === 'save') {
            for (var i = 0; i < this.columns.length; i++) {
                if (this.columns[i].field == "CustomerID") {
                    this.columns[i].visible = false;
                }
                else if (this.columns[i].field == "ShipCountry") {
                    this.columns[i].visible = true;
                    }
                }
        }
    }
</script>
public IActionResult Index()
{
    var Order = OrderDetails.GetAllRecords();
    ViewBag.DataSource = Order;
    return View();
}

Provide custom data source and enabling filtering to DropDownList

You can provide data source to the DropDownList by using the columns.edit.params property.

While setting new data source using edit params, you must specify a new query property too for the DropDownList as follows,

@{
    var DropDownList = new Syncfusion.EJ2.DropDowns.DropDownList() { DataSource = ViewBag.DropDownData, Query = "new ej.data.Query()", Fields = new Syncfusion.EJ2.DropDowns.DropDownListFieldSettings() { Value = "Country", Text = "Country" }, AllowFiltering = true, ActionComplete="actionComplete" };
}
{
    col.Field("ShipName").HeaderText("ShipName").Width("150").EditType("dropdownedit").Edit(new { @params = DropDownList }).Add();
}

You can also enable filtering for the DropDownList by passing the allowFiltering as true to the edit params.

In the below demo, DropDownList is rendered with custom Datasource for the ShipCountry column and enabled filtering to search DropDownList items.

razor
edit-dropdownlist.cs
@{
    var DropDownList = new Syncfusion.EJ2.DropDowns.DropDownList() { DataSource = ViewBag.DropDownData, Query = "new ej.data.Query()", AllowFiltering = true, Fields = new Syncfusion.EJ2.DropDowns.DropDownListFieldSettings() { Value = "Country", Text = "Country" } };
}

@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).Columns(col =>
{
    col.Field("OrderID").HeaderText("Order ID").IsPrimaryKey(true).Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
    col.Field("CustomerID").HeaderText("Customer Name").Width("150").Add();
    col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
    col.Field("ShipName").HeaderText("Ship Name").Width("150").Add();
    col.Field("ShipCountry").HeaderText("Ship Country").Width("150").EditType("dropdownedit").Edit(new { @params = DropDownList }).Add();

}).AllowPaging().EditSettings(edit => { edit.AllowAdding(true).AllowEditing(true).AllowDeleting(true).Mode(Syncfusion.EJ2.Grids.EditMode.Normal); }).Toolbar(new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" }).Render()
public IActionResult Index()
{
    ViewBag.DataSource = OrderDetails.GetAllRecords();
    ViewBag.DropDownData = DropDownDetails.GetAllRecords();
    return View();
}

Access Editor components

You can access the component instance from the component element using the ej2_instances property.

In the below demo, you can access the Editor component instance while adding or editing actions on the ActionComplete event.

razor
access-editor.cs
@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).ActionComplete("access").Columns(col =>
{
   col.Field("OrderID").HeaderText("Order ID").IsPrimaryKey(true).Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("CustomerID").HeaderText("Customer Name").Width("150").Add();
   col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).EditType("numericedit").Add();
   col.Field("ShipCountry").HeaderText("Ship Country").Width("150").EditType("dropdownedit").Add();

}).AllowPaging().EditSettings(edit => { edit.AllowAdding(true).AllowEditing(true).AllowDeleting(true).Mode(Syncfusion.EJ2.Grids.EditMode.Normal); }).Toolbar(new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" }).Render()


<script>

    function access(args) {
        if (args.requestType === 'beginEdit' || args.requestType === 'add') {
            var tr = args.row;
            var numericTextBox = tr.querySelector('.e-numerictextbox'); // numeric TextBox component element
            if (numericTextBox) {
                console.log('NumericTextBox instance: ', numericTextBox.ej2_instances[0]); // numeric TextBox instance
            }
            var dropDownList = tr.querySelector('.e-dropdownlist'); // dropDownList component element
            if (dropDownList) {
                console.log('DropDownList instance: ', dropDownList.ej2_instances[0]); // dropDownList instance
            }
        }
    }
</script>
public IActionResult Index()
{
    var Order = OrderDetails.GetAllRecords();
    ViewBag.DataSource = Order;
    return View();
}

Use Wizard like Dialog Editing

Wizard helps you create intuitive step-by-step forms to fill. You can achieve the wizard like editing by using the dialog template feature. It support your own editing template by defining EditSettings.Mode as Dialog and EditSettings.Template as SCRIPT element ID or HTML string which holds the template.

The following example demonstrate the wizard like editing in the grid with the obtrusive Validation.

The following example demonstrate the wizard like editing in grid.

razor
dialog.cs
@Html.EJS().Grid("DialogTemplateEdit").DataSource((IEnumerable<object>)ViewBag.DataSource).ActionComplete("actionComplete").Columns(col =>
{
   col.Field("OrderID").HeaderText("Order ID").IsPrimaryKey(true).Width("120").ValidationRules(new { required = true }).TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("CustomerID").HeaderText("Customer Name").Width("150").ValidationRules(new { required = true, minLength = 3 }).Add();
   col.Field("ShipCountry").HeaderText("Ship Country").EditType("dropdownedit").Width("150").Add();

}).AllowPaging().PageSettings(page => page.PageCount(2)).EditSettings(edit => { edit.AllowAdding(true).AllowEditing(true).AllowDeleting(true).Mode(Syncfusion.EJ2.Grids.EditMode.Dialog).Template("#dialogtemplate"); }).Toolbar(new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" }).Render()
    

<script>
     function actionComplete(args) {
         if ((args.requestType === 'beginEdit' || args.requestType === 'add')) {
            var countryData = ej.data.DataUtil.distinct(this.dataSource, 'ShipCountry', true);
                new ej.dropdowns.DropDownList({
                    value: args.rowData.ShipCountry, popupHeight: '300px', floatLabelType: 'Always',
                    dataSource: countryData, fields: { text: 'ShipCountry', value: 'ShipCountry' }, placeholder: 'Ship Country'
                }, args.form.elements.namedItem('ShipCountry'));
                new ej.buttons.CheckBox({ label: 'Verified', checked: args.rowData.Verified }, args.form.elements.namedItem('Verified'));
                // Set initail Focus
                if (args.requestType === 'beginEdit') {
                    (args.form.elements.namedItem('CustomerID')).focus();
                }
                initializeWizard();
            }
    }

    function initializeWizard() {
        var currentTab = 0;

        document.getElementById('nextBtn').onclick = function () {
            var grid = document.getElementById("DialogTemplateEdit").ej2_instances[0];
            var valid = true;
            [].slice.call(document.getElementById('tab' + currentTab).querySelectorAll('[name]')).forEach(element => {
                element.form.ej2_instances[0].validate(element.name);
                if (element.getAttribute('aria-invalid') === 'true') {
                    valid = false;
                }
            });
            if (!valid) {
                return
            }
            if (this.innerHTML !== 'SUBMIT') {
                currentTab++;
                nextpre(currentTab);
            } else {
                grid.endEdit();
            }
        }

        document.getElementById('prevBtn').onclick = function () {
            var valid = true;
            [].slice.call(document.getElementById('tab' + currentTab).querySelectorAll('[name]')).forEach(element => {
                element.form.ej2_instances[0].validate(element.name);
                if (element.getAttribute('aria-invalid') === 'true') {
                    valid = false;
                }
            });
            if (!valid) {
                return
            }
            currentTab--;
            nextpre(currentTab);
        }

        function nextpre(current) {
            var tabs = [].slice.call(document.getElementsByClassName('tab'))
            tabs.forEach(element => element.style.display = 'none');
            tabs[current].style.display = '';
            if (current) {
                document.getElementById('prevBtn').style.display = '';
                document.getElementById('nextBtn').innerHTML = 'SUBMIT';
            } else {
                document.getElementById('prevBtn').style.display = 'none';
                document.getElementById('nextBtn').innerHTML = 'NEXT';
            }
        }
    }
 </script>

 <script id='dialogtemplate' type="text/x-template">
     <div>
        <div id="tab0" class='tab'>
           <div class="form-row">
              <div class="form-group col-md-6">
                 <div class="e-float-input e-control-wrapper">
                    <input id="OrderID" required name="OrderID" type="text" value="${if(isAdd)} '' ${else} ${OrderID} ${/if}" disabled="${if(isAdd)} '' ${else} disabled ${/if}" />
                    <span class="e-float-line"></span>
                    <label class="e-float-text e-label-top" for="OrderID">Order ID</label>
                 </div>
              </div>
           </div>
           <div class="form-row">
              <div class="form-group col-md-6">
                 <div class="e-float-input e-control-wrapper">
                    <input id="CustomerID" required name="CustomerID" type="text" value="${if(isAdd)} '' ${else} ${CustomerID} ${/if}" />
                    <span class="e-float-line"></span>
                    <label class="e-float-text e-label-top" for="CustomerID">Customer ID</label>
                 </div>
              </div>
           </div>
        </div>
        <div id=tab1 style="display: none" class='tab'>
           <div class="form-row">
              <div class="form-group col-md-6">
                 <input type="text" name="ShipCountry" id="ShipCountry" value="${if(isAdd)} '' ${else} ${ShipCountry} ${/if}" />
              </div>
            </div>
            <div class="form-row">
               <div class="form-group col-md-6">
                  <input type="checkbox" name="Verified" id="Verified" checked="${if(Verified)} checked ${/if}" />
               </div>
             </div>
         </div>
         <div id='footer'>
            <button id="prevBtn" class="e-info e-btn" type="button" style="display: none; float: left; margin-left: 11px;">Previous</button>

            <button id="nextBtn" class="e-info e-btn" type="button" style="float: right">Next</button>
          </div>
    </div>
</script>
public IActionResult Index()
{
    var Order = OrderDetails.GetAllRecords();
    ViewBag.DataSource = Order;
    return View();
}

Using Tab Inside the Dialog Template

You can use tab component inside dialog edit UI using dialog template feature. The dialog template feature can be enabled by defining EditSettings.Mode as Dialog and EditSetting.Template as SCRIPT element ID or HTML string which holds the template.

The following example demonstrate the usage of tab control inside the dialog template.

razor
dialog.cs
@Html.EJS().Grid("DialogTemplateEdit").DataSource((IEnumerable<object>)ViewBag.DataSource).ActionComplete("actionComplete").Columns(col =>
{
   col.Field("OrderID").HeaderText("Order ID").IsPrimaryKey(true).Width("120").ValidationRules(new { required = true }).TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("CustomerID").HeaderText("Customer Name").Width("150").ValidationRules(new { required = true, minLength = 3 }).Add();
   col.Field("ShipCountry").HeaderText("Ship Country").EditType("dropdownedit").Width("150").Add();

}).AllowPaging().PageSettings(page => page.PageCount(2)).EditSettings(edit => { edit.AllowAdding(true).AllowEditing(true).AllowDeleting(true).Mode(Syncfusion.EJ2.Grids.EditMode.Dialog).Template("#dialogtemplate"); }).Toolbar(new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" }).Render()

<script id='dialogtemplate' type="text/x-template">
    <div>
        <div id="edittab"></div>
        <div id="tab1">
            <div class="form-row">
                <div class="form-group col-md-6">
                    <div class="e-float-input e-control-wrapper">
                        <input id="OrderID" name="OrderID" type="text" value="${if(isAdd)} '' ${else} ${OrderID} ${/if}" disabled="${if(isAdd)} '' ${else} disabled ${/if}" />
                        <span class="e-float-line"></span>
                        <label class="e-float-text e-label-top" for="OrderID">Order ID</label>
                    </div>
                </div>
            </div>
            <div class="form-row">
                <div class="form-group col-md-6">
                    <div class="e-float-input e-control-wrapper">
                        <input id="CustomerID" name="CustomerID" type="text" value="${if(isAdd)} '' ${else} ${CustomerID} ${/if}" />
                        <span class="e-float-line"></span>
                        <label class="e-float-text e-label-top" for="CustomerID">Customer ID</label>
                    </div>
                </div>
            </div>
            <button id='next' class='e-info e-btn' style="float: right" type='button'> next</button>
        </div>

        <div id="tab2" style='display: none'>
            <div class="form-row">
                <div class="form-group col-md-6">
                    <input type="text" name="ShipCountry" id="ShipCountry" value="${if(isAdd)} '' ${else} ${ShipCountry} ${/if}" />
                </div>
            </div>
            <div class="form-row">
                <div class="form-group col-md-6">
                    <input type="checkbox" name="Verified" id="Verified" checked="${if(isAdd)} '' ${else} checked ${/if}" />
                </div>
            </div>
            <button id='submit' class='e-info e-btn' style="float: right" type='button'> submit</button>
        </div>
    </div>
</script>

<script>
    function actionComplete(args) {
        if ((args.requestType === 'beginEdit' || args.requestType === 'add')) {
            var grid = document.getElementById('DialogTemplateEdit').ej2_instances[0];
            var countryData = ej.data.DataUtil.distinct(this.dataSource, 'ShipCountry', true);
            var tabObj = new ej.navigations.Tab({
                showCloseButton: false,
                selecting: function (e) { if (e.isSwiped) { e.cancel = true; } if (e.selectingIndex === 1) { e.cancel = !validate(1) } },
                items: [
                    { header: { 'text': 'Details' }, content: '#tab1' },
                    { header: { 'text': 'Verify' }, content: '#tab2' },
                ]
            });
            tabObj.appendTo('#edittab');

            new ej.dropdowns.DropDownList({
                value: args.rowData.ShipCountry, popupHeight: '200px', floatLabelType: 'Always',
                dataSource: countryData, fields: { text: 'ShipCountry', value: 'ShipCountry' }, placeholder: 'Ship Country'
            }, args.form.elements.namedItem('ShipCountry'));

            new ej.buttons.CheckBox({ label: 'Verified', checked: args.rowData.Verified }, args.form.elements.namedItem('Verified'));
            // Set initail Focus
            if (args.requestType === 'beginEdit') {
                (args.form.elements.namedItem('CustomerID')).focus();
            }
            document.getElementById('next').onclick = () => {
                moveNext();
            }

            function validate(tab) {
                var valid = true;
                [].slice.call(document.getElementById('tab' + tab).querySelectorAll('[name]')).forEach(element => {
                    element.form.ej2_instances[0].validate(element.name);
                    if (element.getAttribute('aria-invalid') === 'true') {
                        valid = false;
                    }
                });
                if (!valid) {
                    return false;
                }
                return true;
            }

            function moveNext() {
                if (validate(1)) {
                    tabObj.select(1);
                }
            }

            document.getElementById('submit').onclick = () => {
                var grid = document.getElementById("DialogTemplateEdit").ej2_instances[0];
                if (validate(2)) {
                    grid.endEdit();
                }
            }
        }
    }
</script>
public IActionResult Index()
{
    var Order = OrderDetails.GetAllRecords();
    ViewBag.DataSource = Order;
    return View();
}

Disable editing for a particular row/cell

You can disable the editing for a particular row by using the ActionBegin event of Grid.

In the below demo, the rows which are having the value for ShipCountry column as “Denmark” is prevented from editing.

razor
disable-edit.cs
@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).AllowPaging().Columns(col =>
{
    col.Field("OrderID").HeaderText("Order ID").IsPrimaryKey(true).Width(30).Add();
    col.Field("CustomerID").HeaderText("Customer ID").Width(30).Add();
    col.Field("ShipCity").HeaderText("Ship City").Width(30).Add();
    col.Field("ShipCountry").HeaderText("Ship Country").Width(30).Add();

}).EditSettings(edit => edit.AllowEditing(true)).Toolbar(new List<string>() { "Edit", "Cancel", "Update" }).ActionBegin("actionBegin").Render()

<script>
    function actionBegin(args) {
        if (args.requestType === "beginEdit") {
            if (args.rowData.ShipCountry == "Denmark") {
                args.cancel = true;
            }
        }
    }
</script>
public IActionResult Index()
{
    ViewBag.DataSource = OrderDetails.GetAllRecords();
    return View();
}

For batch mode of editing, you can use CellEdit event of Grid. In the below demo, the cells which are having the value as “Denmark” is prevented from editing.

razor
disable-edit-batch.cs
@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).AllowPaging().Columns(col =>
{
    col.Field("OrderID").HeaderText("Order ID").IsPrimaryKey(true).Width(30).Add();
    col.Field("CustomerID").HeaderText("Customer ID").Width(30).Add();
    col.Field("ShipCity").HeaderText("Ship City").Width(30).Add();
    col.Field("ShipCountry").HeaderText("Ship Country").Width(30).Add();

}).EditSettings(edit => edit.AllowEditing(true).Mode(Syncfusion.EJ2.Grids.EditMode.Batch)).Toolbar(new List<string>() { "Edit", "Cancel", "Update" }).CellEdit("cellEdit").Render()

<script>
    function cellEdit(args) {
        if (args.value == "Denmark") {
            args.cancel = true;
        }
    }
</script>
public IActionResult Index()
{
    var Order = OrderDetails.GetAllRecords();
    ViewBag.DataSource = Order;
    return View();
}

Perform Grid actions by keyboard shortcut keys

Using keyboard shortcuts, Grid performs navigation and actions.

In addition, You can also perform grid actions with custom keyboard shortcuts. This operation has to be achieved outside of the grid with the help of keydown event.

The following example demonstrates on Adding a new row when Enter key is pressed in the grid.

razor
keys.cs
@using Syncfusion.EJ2


@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).Columns(col =>
{
    col.Field("OrderID").HeaderText("Order ID").IsPrimaryKey(true).Width("120").ValidationRules(new { required = true }).TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
    col.Field("CustomerID").HeaderText("Customer Name").Width("150").Add();
    col.Field("Freight").HeaderText("Freight").EditType("numericedit").Format("C2").Width("150").Add();
    col.Field("ShipCountry").HeaderText("Ship Country").EditType("dropdownedit").Width("150").Add();

}).AllowPaging().PageSettings(page => page.PageCount(2)).EditSettings(edit => { edit.AllowAdding(true).AllowEditing(true).AllowDeleting(true).Mode(Syncfusion.EJ2.Grids.EditMode.Normal); }).Toolbar(new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" }).Render()

<script>
    var grid = document.getElementById("Grid");
    grid.addEventListener("keydown", keyDownHandler)
    function keyDownHandler(e) {
       if (e.keyCode === 13) {
          var gridIns = grid.ej2_instances[0];
          gridIns.addRecord();
       }
    }
 </script>
public IActionResult Index()
{
    var Order = OrderDetails.GetAllRecords();
    ViewBag.DataSource = Order;
    return View();
}

Make a cell editable on a single click with batch editing

You can make a cell editable on a single click with batch mode of editing in Grid, by using the editCell method.

Bind the click event for the Grid and in the click event handler call the editCell method, based on the clicked target element.

razor
editable-single-click.cs
@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).AllowPaging().Columns(col =>
    {
        col.Field("OrderID").HeaderText("Order ID").IsPrimaryKey(true).Width(30).Add();
        col.Field("CustomerID").HeaderText("Customer ID").Width(30).Add();
        col.Field("ShipCity").HeaderText("Ship City").Width(30).Add();
        col.Field("ShipCountry").HeaderText("Ship Country").Width(30).Add();
    }).EditSettings(edit => edit.AllowAdding(true).AllowEditing(true).AllowDeleting(true).Mode(Syncfusion.EJ2.Grids.EditMode.Batch);).Toolbar(new List<string>() { "Add", "Edit", "Delete", "Cancel", "Update" }).Render()

    <script>
        document.getElementById("Grid").addEventListener("click", (e) => {
            if(event.target.classList.contains("e-rowcell")){
                var gridObj = document.getElementsByClassName("e-grid")[0].ej2_instances[0];
                var index = parseInt(event.target.getAttribute("Index"));
                var colindex = parseInt(event.target.getAttribute("aria-colindex"));
                var field = gridObj.getColumns()[colindex].field;
                gridObj.editModule.editCell(index, field);
            }
        });
    </script>
public IActionResult Index()
    {
        var Order = OrderDetails.GetAllRecords();
        ViewBag.DataSource = Order;
        return View();
    }

Filter

Customizing filter menu operators list

You can customize the default filter operator list by defining the FilterSettings.Operators property. The available options are:

  • stringOperator- defines customized string operator list.
  • numberOperator - defines customized number operator list.
  • dateOperator - defines customized date operator list.
  • booleanOperator - defines customized boolean operator list.

In the following sample, we have customized string filter operators.

razor
customize-filter-menu.cs
@{
    List<object> operators = new List<object>();
    operators.Add(new { value = "startswith", text = "starts with" });
    operators.Add(new { value = "endswith", text = "ends with" });
    operators.Add(new { value = "contains", text = "contains" });
}

@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).Columns(col =>
{
    col.Field("OrderID").HeaderText("Order ID").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
    col.Field("CustomerID").HeaderText("Customer Name").Width("150").Add();
    col.Field("OrderDate").HeaderText("Order Date").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Format("yMd").Add();
    col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
    col.Field("ShipCountry").HeaderText("Ship Country").Width("120").Add();

}).AllowFiltering().AllowPaging().FilterSettings(filter => { filter.Type(Syncfusion.EJ2.Grids.FilterType.Menu).Operators(new { stringOperator = operators }); }).Render()
public IActionResult Index()
{
    ViewBag.DataSource = OrderDetails.GetAllRecords();
    return View();
}

Sort

Perform single/multi sorting dynamically

You can perform single-column or multi-column sorting dynamically through an external button.

To perform single-column sorting, use the sortColumn method of Grid.

    document.getElementById('SingleSort').addEventListener('click', () => {
        var grid = document.getElementById("Grid").ej2_instances[0];
        grid.sortColumn("OrderID", "Descending")
    });

To perform multi-column sorting, you need to push the columns to be sorted into the sortSettings.columns.

    document.getElementById('MultiSort').addEventListener('click', () => {
        var grid = document.getElementById("Grid").ej2_instances[0];
        grid.sortModule.sortSettings.columns.push({ field: 'ShipCountry', direction: 'Ascending' }, { field: 'CustomerID', direction: 'Descending' });
        grid.refresh();
    });

In the below demo, click on the corresponding button to perform single-column or multi-column sorting.

razor
dynamicsort.cs
@Html.EJS().Button("SingleSort").Content("Single sort").Render()

    @Html.EJS().Button("MultiSort").Content("Multi sort").Render()

    <div id="GridParent">
    @Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).Columns(col =>
        {
            col.Field("OrderID").HeaderText("Order ID").IsPrimaryKey(true).Width("120").Add();
            col.Field("CustomerID").HeaderText("Customer Name").Width("150").Add();
            col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").Add();
            col.Field("ShipCountry").HeaderText("Ship Country").Width("150").Add();
        }).AllowPaging().AllowSorting().Render()
    </div>

    <script>
        document.getElementById('SingleSort').addEventListener('click', () => {
            var grid = document.getElementById("Grid").ej2_instances[0];
            grid.sortColumn("OrderID", "Descending")
        });

        document.getElementById('MultiSort').addEventListener('click', () => {
            var grid = document.getElementById("Grid").ej2_instances[0];
            grid.sortModule.sortSettings.columns.push({ field: 'ShipCountry', direction: 'Ascending' }, { field: 'CustomerID', direction: 'Descending' });
            grid.refresh();
        });
    </script>
public IActionResult Index()
    {
        var Order = OrderDetails.GetAllRecords();
        ViewBag.DataSource = Order;
        return View();
    }

Dynamically clear sort for particular/entire sorted columns in Grid

You can clear the sorting for a particular column or the entire sorted columns in Grid dynamically through an external button.

To clear sort for a particular column, you need to splice the particular column from the sortSettings.columns.

    document.getElementById('SingleClearSort').addEventListener('click', () => {
        var grid = document.getElementById("Grid").ej2_instances[0];
        var column = grid.sortModule.sortSettings.columns;
        for(var i=0;i < column.length;i++){
            if(column[i].field == "OrderID") {
                column.splice(i,1);
                grid.refresh();
            }
        }
    });

To clear sorting for all the sorted columns, use the clearSorting method of Grid.

    document.getElementById('MultiClearSort').addEventListener('click', () => {
        var grid = document.getElementById("Grid").ej2_instances[0];
        grid.clearSorting();
    });

In the below demo, click on the corresponding button to clear sort for particular or entire sorted columns in Grid.

razor
dynamicclearsort.cs
@Html.EJS().Button("SingleClearSort").Content("Clear the sort for OrderID column").Render()

    @Html.EJS().Button("MultiClearSort").Content("Clear sorting for entire sorted columns").Render()

    @{
        List<object> cols = new List<object>();
        cols.Add(new { field = "OrderID", direction = "Ascending" });
        cols.Add(new { field = "ShipCountry", direction = "Descending" });
    }

    <div id="GridParent">
    @Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).Columns(col =>
        {
            col.Field("OrderID").HeaderText("Order ID").IsPrimaryKey(true).Width("120").Add();
            col.Field("CustomerID").HeaderText("Customer Name").Width("150").Add();
            col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").Add();
            col.Field("ShipCountry").HeaderText("Ship Country").Width("150").Add();
        }).AllowPaging().AllowSorting().SortSettings(sort => sort.Columns(cols)).Render()
    </div>

    <script>
        document.getElementById('SingleClearSort').addEventListener('click', () => {
            var grid = document.getElementById("Grid").ej2_instances[0];
            var column = grid.sortModule.sortSettings.columns;
            for(var i=0;i < column.length;i++){
                if(column[i].field == "OrderID") {
                    column.splice(i,1);
                    grid.refresh();
                }
            }
        });

        document.getElementById('MultiClearSort').addEventListener('click', () => {
            var grid = document.getElementById("Grid").ej2_instances[0];
            grid.clearSorting();
        });
    </script>
public IActionResult Index()
    {
        var Order = OrderDetails.GetAllRecords();
        ViewBag.DataSource = Order;
        return View();
    }

Foreign Key

Use Edit Template in Foreign Key Column

By default, foreign key column uses dropdown component for editing. You can render other than the dropdown by using the Column.Edit property. The following example demonstrates the way of using edit template in foreign column.

In the following example, The Employee Name is a foreign key column and while editing, AutoComplete component is rendered instead of DropDownList.

razor
edit-template-foreign.cs
@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.dataSource).Columns(col =>
{
    col.Field("OrderID").HeaderText("Order ID").IsPrimaryKey(true).Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
    col.Field("EmployeeID").HeaderText("Employee Name").Width("150").ForeignKeyValue("FirstName").DataSource(ViewBag.ForeignData).Edit(new { create = "create", read = "read", destroy = "destroy", write = "write" }).Add();

    col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
    col.Field("ShipName").HeaderText("Ship Name").Width("150").Add();
    col.Field("ShipCountry").HeaderText("Ship Country").Width("150").EditType("dropdownedit").Add();

}).Toolbar(new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" }).AllowPaging().EditSettings(edit => { edit.AllowAdding(true).AllowEditing(true).AllowDeleting(true).Mode(Syncfusion.EJ2.Grids.EditMode.Normal);}).Render()

<script>
    var autoComplete;
    var employeeData = @Html.Raw(Json.Encode(ViewBag.ForeignData));

    function create() { // to create input element
        return document.createElement('input');
    }

    function read () { // return edited value to update data source
       var value = new ej.data.DataManager(employeeData).executeLocal(new ej.data.Query().where('FirstName', 'equal', autoComplete.value));
       return value.length && value[0]['EmployeeID']; // to convert foreign key value to local value.
    }

    function destroy () { // to destroy the custom component.
       autoComplete.destroy();
    }

    function write (args) { // to show the value for custom component
       autoComplete = new ej.dropdowns.AutoComplete({
            dataSource: employeeData,
            fields: { value: args.column.foreignKeyValue },
            value: args.foreignKeyData[0][args.column.foreignKeyValue]
        });
       autoComplete.appendTo(args.element);
}
</script>
public IActionResult Index()
{
    ViewBag.DataSource = OrderDetails.GetAllRecords();
    ViewBag.ForeignData = EmployeeDetails.GetAllRecords();
    return View();
}

Customize filter UI in foreign key column

You can create your own filtering UI by using Column.Filter property. The following example demonstrates the way to create a custom filtering UI in the foreign column.

In the following example, The Employee Name is a foreign key column. DropDownList is rendered using Filter UI.

razor
filter-ui-foreign.cs
@{
    Object filterTemplate = new Object();
    filterTemplate = (new { create = "create", read = "read", write = "write" });
}


@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).Columns(col =>
{
    col.Field("OrderID").HeaderText("Order ID").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
    col.Field("EmployeeID").HeaderText("Employee Name").Width("150").Filter(new { ui = filterTemplate }).ForeignKeyValue("FirstName").DataSource(ViewBag.ForeignData).Add();
    col.Field("OrderDate").HeaderText("Order Date").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Format("yMd").Add();
    col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
    col.Field("ShipCountry").HeaderText("Ship Country").Width("120").Add();

}).AllowFiltering().FilterSettings(filter => filter.Type(Syncfusion.EJ2.Grids.FilterType.Menu)).Render()

<script>
    var dropInstance;
    var fEmployeeData = @Html.Raw(Json.Encode(@ViewData["ForeignData"]));
    function create (args) {
        var flValInput = document.createElement('input');
        flValInput.classList.add('flm-input');
        args.target.appendChild(flValInput);
        dropInstance = new ej.dropdowns.DropDownList({
            dataSource: new ej.data.DataManager(fEmployeeData),
            fields: { text: 'FirstName', value: 'EmployeeID' },
            placeholder: 'Select a value',
            popupHeight: '200px'
        });
        dropInstance.appendTo(flValInput);
    }
    function write (args){
        dropInstance.text = args.filteredValue || '';
    }
    function read (args) {
        args.fltrObj.filterByColumn(args.column.field, args.operator, dropInstance.text);
    }
</script>
public IActionResult Index()
{
    ViewBag.DataSource = OrderDetails.GetAllRecords();
    ViewBag.ForeignData = EmployeeDetails.GetAllRecords();
    return View();
}

Use filter bar template in foreign key column

You can use the filter bar template in foreign key column by defining the column.FilterBarTemplate property. The following example demonstrates the way to use filter bar template in foreign column.

In the following example, The Employee Name is a foreign key column. This column header shows the custom filter bar template and you can select filter value by using the DropDown options.

razor
filterbar-temp-foreign.cs
@{
    Object filterTemplate = new Object();
    filterTemplate = (new { create = "create", read = "read", write = "write" });
}


@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).Columns(col =>
{
    col.Field("OrderID").HeaderText("Order ID").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
    col.Field("EmployeeID").HeaderText("Employee Name").Width("150").FilterBarTemplate(filterTemplate).ForeignKeyField("EmployeeID").ForeignKeyValue("FirstName").DataSource((IEnumerable<object>)ViewBag.ForeignData).Add();
    col.Field("OrderDate").HeaderText("Order Date").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Format("yMd").Add();
    col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
    col.Field("ShipCountry").HeaderText("Ship Country").Width("120").Add();

}).AllowFiltering().Render()

<script>

function create (args) {
    return document.createElement('input', { className: 'flm-input' });
}

function write (args) {
    var fEmployeeData = @Html.Raw(Json.Encode(ViewBag.ForeignData));
    fEmployeeData.splice(0, 0, { 'FirstName': 'All' }); // for clear filtering
    var dropInstance = new ej.dropdowns.DropDownList({
        dataSource: new ej.data.DataManager(fEmployeeData),
        fields: { text: 'FirstName' },
        placeholder: 'Select a value',
        popupHeight: '200px',
        index: 0,
        change: (args) => {
            var grid = document.getElementById("Grid").ej2_instances[0];
            if (args.value !== 'All') {
                grid.filterByColumn('EmployeeID', 'equal', args.value);
            }
            else {
                grid.clearFiltering("EmployeeID");
            }
        }
    });
    dropInstance.appendTo(args.element);
}
</script>
public IActionResult Index()
{
    ViewBag.DataSource = OrderDetails.GetAllRecords();
    ViewBag.ForeignData = EmployeeDetails.GetAllRecords();
    return View();
}

Perform aggregation in Foreign Key Column

Default aggregations are not supported in a foreign key column. You can achieve aggregation for the foreign key column by using the custom aggregates. The following example demonstrates the way to achieve aggregation in foreign key column.

In the following example, The Employee Name is a foreign key column and the aggregation for the foreign column was calculated in customAggregateFn.

razor
aggregate-foreign.cs
@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).Columns(col =>
{
    col.Field("OrderID").HeaderText("Order ID").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
    col.Field("EmployeeID").HeaderText("Employee Name").Width("150").ForeignKeyValue("FirstName").DataSource(ViewBag.ForeignData).Add();
    col.Field("OrderDate").HeaderText("Order Date").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Format("yMd").Add();
    col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
    col.Field("ShipCountry").HeaderText("Ship Country").Width("120").Add();

}).Aggregates(agg => { agg.Columns(new List<Syncfusion.EJ2.Grids.GridAggregateColumn>() { new Syncfusion.EJ2.Grids.GridAggregateColumn() { Field = "EmployeeID", Type = "Custom", CustomAggregate = "customAggregateFn", FooterTemplate = "Count of Margaret: ${Custom}" } }).Add();}).Render()

<script>
    function customAggregateFn(data, column) {
        var grid = document.getElementById("Grid").ej2_instances[0];
        return data.result.filter(function (dObj) {
            return ej.base.getValue('FirstName', ej.grids.getForeignData(grid.getColumnByField(column.columnName), dObj)[0]) === 'Margaret';
        }).length;
    };
</script>
public IActionResult Index()
{
    ViewBag.DataSource = OrderDetails.GetAllRecords();
    ViewBag.ForeignData = EmployeeDetails.GetAllRecords();
    return View();
}

Exporting

Exporting Filtered Data Only

You can export the filtered data by defining the resulted data in exportProperties.dataSource before export.

In the below Pdf exporting demo, We have gotten the filtered data by applying filter query to the grid data and then defines the resulted data in exportProperties.dataSource and pass it to pdfExport method.

razor
export-filtered-data.cs
@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).AllowPdfExport().ToolbarClick("toolbarClick").Columns(col =>
{
   col.Field("OrderID").HeaderText("Order ID").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("CustomerID").HeaderText("Customer Name").Width("150").Add();
   col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("ShipCountry").HeaderText("Ship Country").Width("120").Add();

}).AllowPaging().PageSettings(page => page.PageSize(5).PageCount(5)).AllowFiltering().Toolbar(new List<string>() { "PdfExport" }).Render()
   
<script>
    function toolbarClick(args) {
        var gridObj = document.getElementById("Grid").ej2_instances[0];
        if (args.item.id === 'Grid_pdfexport') {
            var pdfdata;
            var query = gridObj.renderModule.data.generateQuery(); // get grid corresponding query  
            for (var i = 0; i < query.queries.length; i++) {
                if (query.queries[i].fn == 'onPage') {
                    query.queries.splice(i, 1);     // remove page query to get all records
                    break;
                }
            }
            var data = @Html.Raw(Json.Encode(ViewBag.DataSource));
            var fdata = new ej.data.DataManager({ json: data }).executeQuery(query).then((e) => {
                pdfdata = e.result;   // get all filtered records
                var exportProperties = {
                    dataSource: pdfdata,
                };
                gridObj.pdfExport(exportProperties);
            }).catch((e) => true);
        }
    }
</script>
public IActionResult Index()
{
    ViewBag.DataSource = OrderDetails.GetAllRecords();
    return View();
}

Pager

Customize Pager DropDown

To customize default values of pager dropdown, you need to define pageSizes as array of strings.

razor
pagerdropdown.cs
@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).Columns(col =>
{
   col.Field("OrderID").HeaderText("Order ID").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("CustomerID").HeaderText("Customer Name").Width("150").Add();
   col.Field("OrderDate").HeaderText("Order Date").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Format("yMd").Add();
   col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
   col.Field("ShipCountry").HeaderText("Ship Country").Width("120").Add();

}).AllowPaging().PageSettings(page => { page.PageSizes((new string[] { "5", "10", "All" })); }).Render()
public IActionResult Index()
{
    ViewBag.DataSource = OrderDetails.GetAllRecords();
    return View();
}

Hide the expand/collapse icon in parent row when no records in child grid

By default, the expand/collapse icon will be visible even if the child grid is empty.

You can use rowDataBound event to hide the icon when there are no records in child grid.

To hide the expand/collapse icon in parent row when no records in child grid, follow the given steps:

Step 1:

Create CSS class with custom style to override the default style of Grid.

    .e-row[aria-selected="true"] .e-customizedExpandcell {
        background-color: #e0e0e0;
    }

    .e-grid.e-gridhover tr[role='row']:hover {
        background-color: #eee;
    }

Step 2:

Add the CSS class to the Grid in the rowDataBound event handler of Grid.

    function rowDataBound(args) {
        var filter = args.data.EmployeeID;
        var data = new ej.data.DataManager(this.childGrid.dataSource).executeLocal(new ej.data.Query().where("EmployeeID", "equal", parseInt(filter), true));
        if (data.length == 0) {
            //here hide which parent row has no child records
            args.row.querySelector('td').innerHTML = " ";
            args.row.querySelector('td').className = "e-customizedExpandcell";
        }
    }

In the below demo, the expand/collapse icon in the row with EmployeeID as 1 is hidden as it does not have record in child Grid.

razor
hidearrow.cs
@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.DataSource).Load("load").RowDataBound("rowDataBound").Columns(col =>
{
    col.Field("OrderID").HeaderText("Order ID").IsPrimaryKey(true).Width("120").Add();
    col.Field("EmployeeID").HeaderText("Employee ID").Width("150").Add();
    col.Field("Freight").HeaderText("Freight").Width("120").Format("C2").Add();
    col.Field("ShipCountry").HeaderText("Ship Country").Width("150").Add();

}).AllowPaging().Render()

<style>
    .e-row[aria-selected="true"] .e-customizedExpandcell {
        background-color: #e0e0e0;
    }

    .e-grid.e-gridhover tr[role='row']:hover {
        background-color: #eee;
    }
</style>

<script>
    function load(args) {
        var grid = document.getElementById('Grid').ej2_instances[0]
        grid.childGrid = {
            dataSource: dataManger,
            queryString: 'EmployeeID',
            allowPaging: true,
            columns: [
                { field: 'Order', headerText: 'Order ID', textAlign: 'Right', width: 120 },
                { field: 'EmployeeID', headerText: 'Employee ID', width: 120 },
                { field: 'ShipName', headerText: 'Ship Name', width: 150 }
            ],
        }
    }
    var dataManger = [{ Order: 100, ShipName: 'Berlin', EmployeeID: 2 },
        { Order: 101, ShipName: 'Capte', EmployeeID: 3 },
        { Order: 102, ShipName: 'Marlon', EmployeeID: 4 },
        { Order: 103, ShipName: 'Black pearl', EmployeeID: 5 },
        { Order: 104, ShipName: 'Pearl', EmployeeID: 6 },
        { Order: 105, ShipName: 'Noth bay', EmployeeID: 7 },
        { Order: 106, ShipName: 'baratna', EmployeeID: 8 },
        { Order: 107, ShipName: 'Charge', EmployeeID: 9 },
    ];

    function rowDataBound(args) {
        var filter = args.data.EmployeeID;
        var data = new ej.data.DataManager(this.childGrid.dataSource).executeLocal(new ej.data.Query().where("EmployeeID", "equal", parseInt(filter), true));
        if (data.length == 0) {
            //here hide which parent row has no child records
            args.row.querySelector('td').innerHTML = " ";
            args.row.querySelector('td').className = "e-customizedExpandcell";
        }
    }
</script>
public IActionResult Index()
{
    var Order = OrderDetails.GetAllRecords();
    ViewBag.DataSource = Order;
    return View();
}

Render both EJ1 and EJ2 Grids in same application

To achieve this requirement, you need to use the below code in _Layout.cshtml page. Because EJ1 and EJ2 has same library names to perform the different actions. So conflicts may occur when we refer this both controls in same application. To overcome this we need to extend this libraries in ej namespace.

<script>
    var dataCopy = Object.assign({}, ej.data);
    $.extend(ej, Syncfusion);
    $.extend(ej.data, dataCopy);
</script>

The Layout page looks like

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    @* Syncfusion Essential JS 1 Styles *@
    @Styles.Render("http://cdn.syncfusion.com/16.3.0.21/js/web/flat-azure/ej.web.all.min.css")
    @* Syncfusion Essential JS 2 Styles *@
    @Styles.Render("https://cdn.syncfusion.com/ej2/styles/compatibility/material.css")
</head>

<body>
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @Scripts.Render("~/Scripts/jsrender.min.js")
    @* Syncfusion Essential JS 1 Scripts *@
    @Scripts.Render("~/Scripts/ej/web/ej.web.all.min.js")
    @* Syncfusion Essential JS 2 Scripts *@
    @Scripts.Render("~/Scripts/ej2/ej2.min.js")
    @RenderSection("scripts", required: false)

    <script>
        var dataCopy = Object.assign({}, ej.data);
        $.extend(ej, Syncfusion);
        $.extend(ej.data, dataCopy);
    </script>

    <div class="container body-content">
        @RenderBody()
    </div>

    @Html.EJ().ScriptManager()
    @Html.EJS().ScriptManager()
</body>
</html>

How to import localization scripts into grid

For Internationalization and localization usage in grid, you need to include cldr files into your application. Please find the steps to include the cldr-data in your application.

You need to download cldr-data globally in any location by using below command.

npm install cldr-data

After installing cldr-data, you can find cldr-data for all locale in this location.

node_modules->cldr-data->main

You need to copy the required(or all) locale cldr-data and paste into your application folder.

Scripts->cldr->main->paste copied cldr files

You need to include cldr-data into your application and refer file location in index.cshtml file.

razor
localization-scripts.cs
@Html.EJS().Grid("Grid").DataSource((IEnumerable<object>)ViewBag.dataSource).Columns(col =>
    {
        col.Field("OrderID").HeaderText("Order ID").IsPrimaryKey(true).Width("120").Add();
        col.Field("CustomerID").HeaderText("Customer Name").Width("150").Add();
        col.Field("ShipName").HeaderText("Ship Name").Width("150").Add();
        col.Field("Freight").HeaderText("Ship Name").Format("C2").Width("150").Add();
        col.Field("ShipCountry").HeaderText("Ship Country").Width("150").Add();
        
    }).AllowPaging().AllowGrouping().Locale("de").PageSettings(page => page.PageSize(6)).Render()

    <script>
        ej.base.L10n.load({
            'de': {
                'grid': {
                    'EmptyRecord': 'Keine Aufzeichnungen angezeigt',
                    'GroupDropArea': 'Ziehen Sie einen Spaltenkopf hier, um die Gruppe ihre Spalte'
                },
                'pager': {
                    'currentPageInfo': '{0} von {1} Seiten',
                    'totalItemsInfo': '({0} Beiträge)'
                }
            }
        });

        function loadCultureFiles(name) { 
        ej.base.setCulture(name); 
        var files = ['ca-gregorian.json', 'numbers.json', 'timeZoneNames.json']; 
        if (name === 'de') { 
            files.push('numberingSystems.json'); 
        } 
        var loader = ej.base.loadCldr; 
        var loadCulture = function (prop) { 
            var val, ajax; 
            if (name === 'de' && prop === files.length - 1) { 
                ajax = new ej.base.Ajax(location.origin + '/../../scripts/cldr-data/supplemental/' + files[prop], 'GET', false); 
            } else { 
                ajax = new ej.base.Ajax(location.origin + '/../../scripts/cldr-data/main/' + name + '/' + files[prop], 'GET', false); 
            } 
            ajax.onSuccess = function (value) { 
                val = value; 
            }; 
            ajax.send(); 
            loader(JSON.parse(val)); 
        }; 
        for (var prop = 0; prop < files.length; prop++) { 
            loadCulture(prop); 
        } 
    } 
 
    document.addEventListener('DOMContentLoaded', function () { 
        loadCultureFiles('de'); 
    }); 
    </script>
public IActionResult Index()
    {
        var orders =OrderDetails.GetAllRecords();
        ViewBag.datasource = orders;            
        return View();
    }

Render Grid from Controller

To render grid from controller, We need to create instance for Grid model class. Also we need to define the values for the Grid properties by using this instance. Once the values are defined, we need to return the Grid instance in view to render the Grid in view page.

razor
controller.cs
@model Syncfusion.EJ2.Grids.Grid

@Html.EJS().Grid("Grid", Model).Render()
public class HomeController : Controller
    {
        public static List<Orders> order = new List<Orders>();
        public ActionResult Index()
        {
            Syncfusion.EJ2.Grids.Grid gridProp = new Syncfusion.EJ2.Grids.Grid();
            gridProp.AllowPaging = true;
            gridProp.DataSource = order;
            gridProp.EditSettings = new Syncfusion.EJ2.Grids.GridEditSettings() { AllowEditing = true, AllowDeleting = true, AllowAdding = true };
            List<object> col = new List<object>();
            gridProp.Toolbar = new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" };
            col.Add(new { field = "OrderID", isPrimaryKey = true, headerText = "OrderID", width = "120" });
            col.Add(new { field = "CustomerID", headerText = "CustomerID", width = "120" });
            col.Add(new { field = "EmployeeID", headerText = "EmployeeID", width = "120" });
            gridProp.Columns = col;
            return View(gridProp);
        }
    }