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").CssClass('e-block').IsPrimary(true).Render();
@Html.EJS().Button("delete").Content("Delete").CssClass('e-block').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) };
    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) {
        let selectedRow: number = 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()
    <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().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()
    </div>

    <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="ContactName", HeaderText="Name", Width="100" },
                new Syncfusion.EJ2.Grids.GridColumn(){ Field="CompanyName", HeaderText="Company", Width="120" },
                new Syncfusion.EJ2.Grids.GridColumn(){ Field="Country", HeaderText="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("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().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(grid, 'Expanded', args.previousPage ));
        }
    }
    function load() {
        if (this.isPrinting) {
            this.expandedRows = ej.base.extend({}, expandedChildGrid, this.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();
   }).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();
   }).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.
        let tooltip = 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: "\e941";
      }   
   </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("Grid")
            .DataSource(dm => dm.Url("Home/DataSource")
                                .InsertUrl("Home/Insert")
                                .UpdateUrl("Home/Update")
                                .RemoveUrl("Home/Delete")
                                .Adaptor("UrlAdaptor"))
            .Load("load").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("EmployeeID").HeaderText("Employee ID").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()
public class HomeController : Controller
{
    static List<OrderData> vData = new List<OrderData>();
    
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult DataSource(Data Dm)
    {
        var DataSource = getData().ToList();
        int count = DataSource.Count();
        return Json(new { result = DataSource.Skip(Dm.skip).Take(Dm.take), count = count });

    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Insert(OrderData value,string token)
    {

        getData().Insert(0, value);
        
        return Json(getData());
    }
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Update(OrderData value)
    {

        OrderData ord = getData().Where(r => r.OrderID == value.OrderID).FirstOrDefault();
        {
            ord.OrderID = value.OrderID;
            ord.CustomerID = value.CustomerID;
            ord.Freight = value.Freight;
            ord.EmployeeID = value.EmployeeID;
            ord.ShipCity = value.ShipCity;
        }

        return Json(ord);
    }
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Delete(int key)
    {

        var itemToRemove = getData().Where(ord => ord.OrderID == key).SingleOrDefault();
        if (itemToRemove != null)
            getData().Remove(itemToRemove);

        return Json(getData());
    }
}

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

@section ControlsSection{
    <div class="control-section">
        @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()
    </div>
   
    <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" }, ActionComplete="actionComplete" };
}
@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()

<script>
function actionComplete() {
        return false;
    }
</script>
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).ActionBegin("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
@{
    ViewBag.Title = "DialogTemplateEdit";
}

@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).Template("#dialogtemplate"); }).Toolbar(new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" }).Render()
    </div>
   
    <script>
        function actionComplete(args) {
            if ((args.requestType === 'beginEdit' || args.requestType === 'add')) {
                let countryData = ej.data.DataUtil.distinct(data, '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.inputs.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() {
    let currentTab = 0;

    document.getElementById('nextBtn').onclick = function () {
        let 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 () {
        let 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) {
        let 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}  ${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" ${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">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
@{
    ViewBag.Title = "DialogTemplateEdit";
}

@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).Template("#dialogtemplate"); }).Toolbar(new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" }).Render()
    </div>
   
    <script>
        actionComplete: (args) => {
            if ((args.requestType === 'beginEdit' || args.requestType === 'add')) {
            let grid = document.getElementById('Grid').ej2_instances[0];
            let countryData = ej.data.DataUtil.distinct(data, 'ShipCountry', true);
            let 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', disabled: true },
                ]
            });
            tabObj.appendTo('#edittab');

            new ej.dropdown.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.inputs.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) {
                let valid: boolean = 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 = () => {
                if (validate(2)) {
                    grid.endEdit();
                }
            }
        }
    }
    </script>

    <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} ${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" ${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>
}
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)).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

@section ControlsSection{
    <div class="control-section">
        @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()
    </div>
   
    <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();
}

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().FilterSettings(filter => { filter.Type(Syncfusion.EJ2.Grids.FilterType.Menu).Operators(new { stringOperator = operators }); }).Render()
public IActionResult Index()
{
    ViewBag.DataSource = OrderDetails.GetAllRecords();
    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();

}).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>
    var autoComplete;
var employeeData = @Html.Raw(Json.Encode(@ViewData["ForeignData"]));
function create () { // to create input element
    return createElement('input');
}
    function read () { // return edited value to update data source
    let value = new ej.data.DataManager(employeeData).executeLocal(new ej.data.Query().where('LastName', '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
@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(filter => filter.ui(new { create = "create", read = "read", write = "write" });).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().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
@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=(new {ui={create="create", read="read", write="write"}})
       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()
    .Render()

<script>

function create (args) {
    return createElement('input', { className: 'flm-input' });;
}
function write (args) {
    var fEmployeeData = @Html.Raw(Json.Encode(@ViewData["ForeignData"])).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) => {
            if (args.value !== 'All') {
                grid.filterByColumn('EmployeeID', 'equal', args.value);
            }
            else {
                grid.removeFilteredColsByField('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) {
        let grid = document.getElementById("Grid").ej2_instances[0];
        return data.result.filter(function(dObj){
            return 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("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.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.Serialize(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();
    }