Copied RSS Feed

JavaScript

How to Bulk Edit Columns in JavaScript DataGrid

The Syncfusion JavaSript DataGrid control is a high-performance grid component that helps display and manipulate large amounts of data in a tabular format. Its feature set includes rich functionalities: data binding, sorting, grouping, editing, filtering, swiping, dragging, resizing, loading more items, pull-to-refresh, and exporting to Excel and PDF file formats. In this blog, we are going to walk you through the procedure to implement column bulk-edit support for the JavaScript DataGrid (ES5 platform) through the context menu event, also known as a right-click event.

Column bulk editing is a feature that helps us easily edit multiple cells in a column at once in JavaScript DataGrid. It saves a lot of time and reduces the workload. We’ll start this blog by creating a sample of a simple  JavaScript DataGrid project with remote data binding. Then, I’ll show you the edit dialog with the desired column type when right-clicking on a grid column.

Let’s see about them along with code examples!

Create JS DataGrid sample

Please follow these steps to render the DataGrid in the JavaScript platform (ES5).

Step 1: First, let’s create the index.html file with a JS CDN (content delivery network) script reference like in the following code.

<html>

<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" charset="utf-8" />
    <script src="https://cdn.syncfusion.com/ej2/dist/ej2.min.js" type="text/javascript"></script>
    <link href="https://cdn.syncfusion.com/ej2/material.css" rel="stylesheet">
    
    <style>
        body {
            touch-action: none;
        }

        .e-grid {
            margin: 30px;
        }

        .title {
            text-align: center;
        }
    </style>
</head>

<body>
    <div class="stackblitz-container material">
        <div class="control-section">
            <div class="content-wrapper">
                <h4 class="title">Multi Column Update</h4>
                <div id="sample"></div>
            </div>

        </div>
    </div>
</body>

</html>

Step 2: Here, we will use the DataGrid to display employees’ details. So, let’s create the employee.js file and add the following basic grid rendering codes to it.

function renderGrid() {

    gridInstance = new ej.grids.Grid({
        columns: [
            { field: "EmpID", isPrimaryKey: true, allowEditing: false },
            {
                field: "Name",
                headerText: "Employee Name",
                validationRules: { required: true }
            },
            

        ],
        dataSource: [],
        height: "auto",
        allowPaging: true,
        pageSettings: { pageSize: 15 },
        selectionSettings: { type: "Multiple", persistSelection: true }

    });
    document.body.appendChild(ej.base.createElement("div", { id: "sample" }));
    gridInstance.appendTo("#sample");
}

// event triggered when DOM load complete.
document.addEventListener('DOMContentLoaded', (event) => {
    //Render grid
    renderGrid();
});

Step 3: Then, add this Employee.js file as the source in the index.html.

Step 4: Now, open the index.html file. It will display the created grid sample with two columns, Id and Employee Name, like in the following screenshot.

Note: Please refer to the Getting Started documentation to render the DataGrid in the JavaScript platform (ES5).

API implementation and data binding

Here, I have created an ASP.NET Core application for the API implementation.

Install the necessary NuGet packages

Step 1: Right-click on the project and choose the Manage NuGet Packages option like in the following screenshot.

Step 2: Now, switch to the Browse tab and search for the Syncfusion.EJ2.AspNet.Core NuGet package. Then, install it in your application.

Employee list Get API

In the ASP.NET Core application sample, no database connection is used. Employee records are stored in the static property and returned as an API response.

Refer to the following code.

public static List<EmployeeDetails> GetAllRecords()
  {
      List<EmployeeDetails> empList = new List<EmployeeDetails>();
      empList.Add(new EmployeeDetails() { EmpID = 1, PhoneNumber = 412134, Name = "Raja", Designation = "Software Engineer", Reporter = "Selva", BranchLocation = "Eymard", TeamName = "Consulting", DateOfJoin = new DateTime(2018, 06, 01), EmpStatus = "Confirmed" });
      empList.Add(new EmployeeDetails() { EmpID = 2, PhoneNumber = 333111, Name = "Suresh", Designation = "Software Engineer", Reporter = "Selva", BranchLocation = "Eymard", TeamName = "Consulting", DateOfJoin = new DateTime(2020, 02, 01), EmpStatus = "Probation" });
      empList.Add(new EmployeeDetails() { EmpID = 3, PhoneNumber = 431891, Name = "Selva", Designation = "Team Lead", Reporter = "Karthik", BranchLocation = "Eymard", TeamName = "Consulting", DateOfJoin = new DateTime(2013, 02, 01), EmpStatus = "Confirmed" });
      empList.Add(new EmployeeDetails() { EmpID = 4, PhoneNumber = 312211, Name = "Guna", Designation = "Software Engineer", Reporter = "Selva", BranchLocation = "Eymard", TeamName = "Consulting", DateOfJoin = new DateTime(2015, 01, 01), EmpStatus = "Confirmed" });
      empList.Add(new EmployeeDetails() { EmpID = 5, PhoneNumber = 412134, Name = "Ravi", Designation = "Software Engineer", Reporter = "Selva", BranchLocation = "Eymard", TeamName = "Consulting", DateOfJoin = new DateTime(2019, 03, 01), EmpStatus = "Confirmed" });
      empList.Add(new EmployeeDetails() { EmpID = 6, PhoneNumber = 412135, Name = "Priya", Designation = "Software Engineer", Reporter = "Selva", BranchLocation = "Eymard", TeamName = "Consulting", DateOfJoin = new DateTime(2015, 07, 01), EmpStatus = "Confirmed" });
      empList.Add(new EmployeeDetails() { EmpID = 7, PhoneNumber = 412136, Name = "Dhana", Designation = "Software Engineer", Reporter = "Vino", BranchLocation = "Mathura", TeamName = "Consulting", DateOfJoin = new DateTime(2015, 09, 01), EmpStatus = "Confirmed" });
      empList.Add(new EmployeeDetails() { EmpID = 8, PhoneNumber = 412137, Name = "Karthik", Designation = "Manager", Reporter = "", BranchLocation = "Mathura", TeamName = "Consulting", DateOfJoin = new DateTime(2010, 02, 01), EmpStatus = "Confirmed" });
      empList.Add(new EmployeeDetails() { EmpID = 9, PhoneNumber = 411138, Name = "Vino", Designation = "Team Lead", Reporter = "Raj", BranchLocation = "Mathura", TeamName = "Consulting", DateOfJoin = new DateTime(2014, 02, 01), EmpStatus = "Confirmed" });
      empList.Add(new EmployeeDetails() { EmpID = 10,PhoneNumber = 412139,  Name = "Raji", Designation = "Software Engineer", Reporter = "Vino", BranchLocation = "Mathura", TeamName = "Consulting", DateOfJoin = new DateTime(2015, 05, 01), EmpStatus = "Probation" });
      empList.Add(new EmployeeDetails() { EmpID = 11,PhoneNumber = 412140,  Name = "Vijay", Designation = "Software Engineer", Reporter = "Vino", BranchLocation = "Mathura", TeamName = "Consulting", DateOfJoin = new DateTime(2020, 02, 01), EmpStatus = "Confirmed" });
      empList.Add(new EmployeeDetails() { EmpID = 12,PhoneNumber = 412141,  Name = "Raj", Designation = "Manager", Reporter = "", BranchLocation = "Mathura", TeamName = "Consulting", DateOfJoin = new DateTime(2010, 02, 01), EmpStatus = "Confirmed" });
      return empList;
  }

Implement the Get API to return all the employee records.

public IActionResult GetEmployees([FromBody]DataManagerRequest dm)
 {
      IEnumerable DataSource = Employees;
      DataOperations operation = new DataOperations();
            
      int count = DataSource.Cast<EmployeeDetails>().Count();
      if (dm.Skip != 0)
      {
         DataSource = operation.PerformSkip(DataSource, dm.Skip);   //Paging
      }
      if (dm.Take != 0)
      {
         DataSource = operation.PerformTake(DataSource, dm.Take);
      }
      return dm.RequiresCounts ? Json(new { result = DataSource, count = count }) : Json(DataSource);
 }

Note:

The modal object class DataManagerRequest is referenced from the library using Syncfusion.EJ2.Base.

Employee Update API

Implement the bulk-record update logic like in the following code example.

public IActionResult UpdateEmployeeDetails([FromBody]CRUDModel<EmployeeDetails> batchmodel)
  {
     if (batchmodel != null && batchmodel.Changed != null)
     {
         for (var i = 0; i < batchmodel.Changed.Count(); i++)
         {
              var ord = batchmodel.Changed[i];
              EmployeeDetails val = Employees.Where(or => or.EmpID == ord.EmpID).FirstOrDefault();
              val.EmpID = ord.EmpID;
              val.Name = ord.Name;
              val.Designation = ord.Designation;
              val.BranchLocation = ord.BranchLocation;
              val.Reporter = ord.Reporter;
              val.EmpStatus = ord.EmpStatus;
              val.DateOfJoin = ord.DateOfJoin;
              val.TeamName = ord.TeamName;
              val.PhoneNumber = ord.PhoneNumber;
          }
      }
      var data = Employees.ToList();
      return Json(data);
  }

Note:

The modal object class CRUDModal is referenced from the library using Syncfusion.EJ2.Base.

Remote data binding

Now, follow these steps to bind the Get and Update APIs to the grid.

Step 1: Switch to the Employee.js file and create an instance of DataManager with both the Get (url) and Update (crudUrl) URLs.

var hostUrl = "http://localhost:64515/";

var gridDataSource = new ej.data.DataManager({
    url: hostUrl + "Employee/GetEmployees",
    crudUrl: hostUrl + "Employee/UpdateEmployeeDetails",
    adaptor: new ej.data.UrlAdaptor()
});

Note: We should provide the server API running the URL  as the hostUrl in the js file.

Step 2: Then, assign the DataManager instance to the grid’s dataSource property.

Sample code

function renderGrid() {

    gridInstance = new ej.grids.Grid({
        columns: [
            { field: "EmpID", isPrimaryKey: true, allowEditing: false },
            {
                field: "Name",
                headerText: "Employee Name",
                validationRules: { required: true }
            },
            
        ],
        dataSource: gridDataSource,
        height: "auto",
        allowPaging: true,
        pageSettings: { pageSize: 15 },
        selectionSettings: { type: "Multiple", persistSelection: true }

    });
    document.body.appendChild(ej.base.createElement("div", { id: "sample" }));
    gridInstance.appendTo("#sample");
}

Step 3: Now, configure the grid column settings to display the employee details in the grid.

function renderGrid() {

    gridInstance = new ej.grids.Grid({
        columns: [
            { field: "EmpID", isPrimaryKey: true, allowEditing: false },
            {
                field: "Name",
                headerText: "Employee Name",
                validationRules: { required: true }
            },
            {
                field: "Designation",
                headerText: "Designation"
            },
            {
                field: "TeamName",
                headerText: "Team"
            },
            {
                field: "PhoneNumber",
                headerText: "Phone",
                type: "number"
            },
            {
                field: "Reporter",
                headerText: "Reporter",
                editType: "dropdownedit",
                foreignKeyField: "ReporterId",
                foreignKeyValue: "Reporter",
                dataSource: Reporters
            },
            {
                field: "BranchLocation",
                headerText: "Branch"
            },
            {
                field: "DateOfJoin",
                headerText: "Date Of Joined",
                type: "date",
                format: { type: "date", format: "MMM dd yyyy" },
                editType: "datepickeredit",
                edit: { params: { format: "MMM dd yyyy" } }
            },
            {
                field: "EmpStatus",
                headerText: "Status",
                editType: "dropdownedit",
                foreignKeyField: "EmpStatusId",
                foreignKeyValue: "EmpStatus",
                dataSource: StatusList
            }

        ],
        dataSource: gridDataSource,
        height: "auto",
        allowPaging: true,
        pageSettings: { pageSize: 15 },
        selectionSettings: { type: "Multiple", persistSelection: true }

    });
    document.body.appendChild(ej.base.createElement("div", { id: "sample" }));
    gridInstance.appendTo("#sample");
}

Step 4: Then, save all the files and run the server API.

Step 5: After successfully running the API host, open the index.html file. It will show you the grid with the given static employee data.

Now, we have finished the API implementation and bound the remote data to the DataGrid.

Display edit dialog in the context menu

Now, add a reference to Ej2GridExtendedFeature.js in the grid page (Index.html) like in the following screenshot.

Note: You can download the script file.

Enable bulk-edit feature

Now, we are going to invoke the enableBulkColumnEdit() method from the created event of the JavaScript DataGrid to enable the column bulk-edit feature.

Refer to the following screenshot.

Sample code

function renderGrid() {

    gridInstance = new ej.grids.Grid({
        columns: [
            { field: "EmpID", isPrimaryKey: true, allowEditing: false },
            {
                field: "Name",
                headerText: "Employee Name",
                validationRules: { required: true }
            },
            {
                field: "Designation",
                headerText: "Designation"
            },
            {
                field: "TeamName",
                headerText: "Team"
            },
            {
                field: "PhoneNumber",
                headerText: "Phone",
                type: "number"
            },
            {
                field: "Reporter",
                headerText: "Reporter",
                editType: "dropdownedit",
                foreignKeyField: "ReporterId",
                foreignKeyValue: "Reporter",
                dataSource: Reporters
            },
            {
                field: "BranchLocation",
                headerText: "Branch"
            },
            {
                field: "DateOfJoin",
                headerText: "Date Of Joined",
                type: "date",
                format: { type: "date", format: "MMM dd yyyy" },
                editType: "datepickeredit",
                edit: { params: { format: "MMM dd yyyy" } }
            },
            {
                field: "EmpStatus",
                headerText: "Status",
                editType: "dropdownedit",
                foreignKeyField: "EmpStatusId",
                foreignKeyValue: "EmpStatus",
                dataSource: StatusList
            }

        ],
        dataSource: gridDataSource,
        height: "auto",
        created: onCreated,
        allowPaging: true,
        pageSettings: { pageSize: 15 },
        selectionSettings: { type: "Multiple", persistSelection: true }

    });
    document.body.appendChild(ej.base.createElement("div", { id: "sample" }));
    gridInstance.appendTo("#sample");
}


function onCreated(args) {
    //Enable multicolumn edit.
    try {
        // pass grid instance and Data-manager instance as parameters to enable column bulk-edit feature.
        enableBulkColumnEdit(this, gridDataSource);
    }
    catch (ex) {
        console.log("Refer Ej2GridExtendedFeature.js to enable Column bulk edit. InnerException "+ ex);
    }
}

Note: Enabling the column bulk-edit feature will override the Context Menu event and selection setting of the grid.

Logic behind the detailed view of Ej2GridExtendedFeature.js file

In this section, we are going to see the implementation logic used in the script file Ej2GridExtendedFeature.js, which helps developers customize the column bulk-edit feature in JavaScript DataGrid if needed.

Create dialog

Create the edit dialog dynamically during the page rendering. This dialog will show the desired editor when right-clicking on the grid column.

Please find the logic in the create_InitializeEditModal() method in the Ej2GridExtendedFeature.js file.

Sample code

 function create_InitializeEditModal() {
    var modalContainerEle = document.createElement("div");
    modalContainerEle.id = "BulkEdit-dialog-container";
    var modalEle = document.createElement("div");
    modalEle.id = "dialogBulkEdit";
    var inputContainerEle = document.createElement("div");
    inputContainerEle.id = "modal-editor-container";

    modalEle.appendChild(inputContainerEle);
    modalContainerEle.appendChild(modalEle);
    document.body.appendChild(modalContainerEle);

    editDialogInstance = new ej.popups.Dialog({
        target: document.getElementById("BulkEdit-dialog-container"),
        width: '350px',
        showCloseIcon: true,
        position: { X: 'center', Y: 'center' },
        visible: false,
        buttons: [
            {
                'click': onClickSaveBtn,
                buttonModel: {
                    isPrimary: true,
                    content: 'Save'
                }
            },
            {
                'click': onClickCancelBtn,
                buttonModel: {
                    content: 'Cancel'
                }
            }
        ]

    });

    // Render/initialized Dialog
    editDialogInstance.appendTo('#dialogBulkEdit');
    modalEle.style.top = '100px';
}

Bind context menu event to custom function

Here we bind the customer gridRightClickHandler() to the contextmenu event of the grid.

Create dynamic editor

Right-click on the DataGrid column, create the editor element dynamically, and append it to the bulk edit modal, based on the current column data type.

Please find the dynamic editor creation logic in the gridRightClickHandler() method definition.

Sample code

 if (editColumnType === DATA_TYPE.STRING && editType === EDIT_TYPE.DROPDOWN_EDIT) {
                var dataSource = [];

                if (curRowInfo.column.dataSource) {
                    dataSource = curRowInfo.column.dataSource;
                }
                inputEditorInstance = new ej.dropdowns.DropDownList({
                    placeholder: "Select " + editFieldName,
                    popupHeight: "200px",
                    dataSource: dataSource,
                    fields: { text: currentEditColumn, value: currentEditColumn }
                });
            }
            else if (editColumnType === DATA_TYPE.STRING) {
                inputEditorInstance = new ej.inputs.TextBox({
                    placeholder: editFieldName
                });
            }
            else if (editColumnType === DATA_TYPE.DATE) {
                var format = "dd/MMM/yyyy";

                if (curRowInfo.column.format && curRowInfo.column.format.format) {
                    format = curRowInfo.column.format.format;
                }
                else if (curRowInfo.column.format) {
                    format = curRowInfo.column.format;
                }

                inputEditorInstance = new ej.calendars.DatePicker({
                    format: format,
                    placeholder: "Select " + editFieldName
                });
            }
            else if (editColumnType === DATA_TYPE.NUMBER) {

                inputEditorInstance = new ej.inputs.NumericTextBox({
                    placeholder: editFieldName
                });
            }

The editor will be displayed based on the column setting. Refer to the following table.

Column Setting Result Screenshot
Type: Numeric

Example:

 gridInstance = new ej.grids.Grid({

columns: [

…

{

field: "PhoneNumber",

headerText: "Phone",

type: "number"

},

…

]

});
Numeric text box will be displayed.
Type: string

Example:

 gridInstance = new ej.grids.Grid({

columns: [

…

{

field: "Name",

headerText: "Employee Name",

validationRules: { required: true }

}

…

]

});
Text box will be displayed.

Note: If the type is not specified, then it will automatically set the first record value type as the column data type.

Column validation

The bulk-edit dialog will always be created with form. If the current right-clicked column has a validation rule, then it will be added to the edit form. (If there is no validation rule, then the validation will not be applied.)

Please find the validation rule add logic in the gridRightClickHandler() method definition. Refer to the following sample code.

if (inputEditorInstance) {
                setTimeout(function () {
                    inputEditorInstance.appendTo("#input-element");
                    /**
                     * Add validation rule to edit modal input field
                     */                    if (curRowInfo.column.validationRules) {
                        var validationOptions = {
                            rules: {}
                        };
                        validationOptions.rules[currentEditColumn] = curRowInfo.column.validationRules;

                        formInstance = new ej.inputs.FormValidator('#' + editFormId, validationOptions);
                    }
                    // Edit dialog is displayed
                    editDialogInstance.show();
                }, 100);
            }

So, whenever you click on the Save button, the data will be validated (if form has any validation rule).

Format and save dialog data

After successful form validation, the save object will be formatted for all the selected records and then saved using the DataManager instance.

Refer to the following code.

function onClickSaveBtn() {
    var editableRows = gridInstance.getSelectedRecords();
    var changes = { changedRecords: [], addedRecords: [], deletedRecords: [] };

    if ((formInstance && formInstance.validate()) || (formInstance === null)) {

        if (currentEditColumn) {
            for (var k = 0; k < editableRows.length; k++) {
                var updateObj = {};
                var newValue = "";
                newValue = inputEditorInstance.value;

                updateObj = editableRows[k];
                updateObj[currentEditColumn] = newValue;
                changes.changedRecords.push(updateObj);
            }

            gridDataSource.saveChanges(changes, primaryKeyColumnField).then(e => {
                // Grid is refreshed with updated data
                gridInstance.refreshColumns();
            });

            // Previous changes are removed and dialog is hidden
            changes = { changedRecords: [], addedRecords: [], deletedRecords: [] };
            currentEditColumn = "";
            editDialogInstance.hide();
        }
    }
}

Supported column edit types

In this blog, the Ej2GridExtendedFeature.js file has support for the following grid column edit types:

  • NumericTextBox
  • TextBox
  • DropDownList
  • DatePicker
  • DateTimePicker

Note: Please refer to Cell edit type and its params documentation.

Points to remember

  • DataGrid should contain at least one Primary Key column.
  • We should pass the DataGrid instance and Data Manager instance as arguments to enable the column bulk edit feature.

Reference

You can download the demo video on our website.

For further reference, you can checkout Bulk Edit Columns in JavaScript DataGrid sample.

How to run the sample

Follow these steps to run the sample:

  1. Extract the previously attached source given in the reference section.
  2. Run the server source by opening EmployeeDetailsGrid.sln. Refer to the following screenshot.
  3. Navigate to the path ../client/Employee.js and ensure the hosted server URL.
  4. Open the index.html file. Now, you can enjoy the column bulk edit feature in the JavaScript DataGrid.

    Bulk Edit Columns in JavaScript DataGrid

Conclusion

In this blog, we have learned how to implement the column bulk edit feature in the Syncfusion  JavaScript DataGrid. With this, you can easily update multiple cells in a column at once, which saves a lot of time and reduces your workload. I hope you found this blog useful. Try out the steps given in this blog and leave your feedback in the comments section below.

Syncfusion DataGrid is also available in the Blazor, ASP.NET (Core, MVC, WebForms), Angular, React , Vue, Xamarin, Flutter, UWP, WinForms, WPF, and WinUI platforms. For existing customers, the new version is available for download from the License and Downloads page. If you are not yet a Syncfusion customer, you can try our 30-day free trial to check out our available features.

For questions, you can contact us through our support forumDirect-Trac, or feedback portal. We are always happy to assist you!

If you liked this blog post, we think you’ll also like the following articles:

Meet the Author

Vijayaraj Angappan

I am a full stack developer at Syncfusion and am a part of the consulting team. I am fascinated by new technologies and would like to work with the latest web platforms from scratch.