Batch editing in Vue Grid component

28 Mar 202324 minutes to read

In Batch edit mode, when you double-click on the grid cell, then the target cell changed to edit state.You can bulk save (added, changed and deleted data in the single request) to data source by click on the toolbar’s Update button or by externally invoking the batchSave method. To enable Batch edit, set the editSettings.mode as Batch.

<template>
    <div id="app">
        <ejs-grid :dataSource='data' :editSettings='editSettings' :toolbar='toolbar' height='273px'>
            <e-columns>
                <e-column field='OrderID' headerText='Order ID' textAlign='Right' :isPrimaryKey='true' width=100></e-column>
                <e-column field='CustomerID' headerText='Customer ID' width=120 allowEditing='false'></e-column>
                <e-column field='Freight' headerText='Freight' textAlign= 'Right' editType= 'numericedit' width=120 format= 'C2'></e-column>
                <e-column field='ShipCountry' headerText='Ship Country' editType= 'dropdownedit' width=150></e-column>
            </e-columns>
        </ejs-grid>
    </div>
</template>
<script>
import Vue from "vue";
import { GridPlugin, Page, Toolbar, Edit } from "@syncfusion/ej2-vue-grids";
import { data } from './datasource.js';

Vue.use(GridPlugin);

export default {
  data() {
    return {
      data: data,
      editSettings: { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Batch' },
      toolbar: ['Add', 'Edit', 'Delete', 'Update', 'Cancel']
    };
  },
  provide: {
    grid: [Page, Edit, Toolbar]
  }
}
</script>
<style>
 @import "../node_modules/@syncfusion/ej2-vue-grids/styles/material.css";
</style>

If a column’s allowEditing property is set to false, then the focus can be skipped in that non-editable column by clicking the tab or shift-tab key while in batch edit mode.

Automatically update the column based on another column edited value in batch mode

You can update the column value based on another column edited value in Batch mode by using the Cell Edit Template feature.

In the below demo, we have update the TotalCost column value based on the UnitPrice and UnitInStock column value while editing.

<template>
  <div id="app">
    <ejs-grid id="Grid1" :dataSource="data" :editSettings="editSettings" :toolbar="toolbar" height="273px" :cellEdit="cellEdit">
      <e-columns>
        <e-column field="ProductID" headerText="Product ID" textAlign="Right" :isPrimaryKey="true" width="100"></e-column>
        <e-column field="ProductName" headerText="Product Name" width="120"></e-column>
        <e-column field="UnitPrice" headerText="Unit Price" editType="numericedit" :edit="priceParams"
          width="150" format="C2" textAlign="Right" ></e-column>
        <e-column field="UnitsInStock" headerText="Units In Stock" editType="numericedit"
          :edit="stockParams" width="150" textAlign="Right"></e-column>
        <e-column field="TotalCost" headerText="Total Cost" width="150" format="C2" textAlign="Right" ></e-column>
      </e-columns>
    </ejs-grid>
  </div>
</template>
<script>
import Vue from "vue";
import { GridPlugin, Toolbar, Edit } from "@syncfusion/ej2-vue-grids";
import { NumericTextBox } from "@syncfusion/ej2-inputs";
import { productData } from "./datasource.js";
import { getComponent } from "@syncfusion/ej2-base";

let priceElem, stockElem, priceObj, stockObj;
var grid;
Vue.use(GridPlugin);
export default {
  data: () => {
    return {
      data: productData,
      toolbar: ["Add", "Delete", "Update", "Cancel"],
      editSettings: {
        allowEditing: true,
        allowAdding: true,
        allowDeleting: true,
        mode: "Batch",
      },
      priceParams: {
        create: () => {
          priceElem = document.createElement("input");
          return priceElem;
        },
        read: () => {
          return priceObj.value;
        },
        destroy: () => {
          priceObj.destroy();
        },
        write: (args) => {
         grid = new getComponent("Grid1", "grid");
          var rowData = args.rowData;
          var rowIndex = grid.getRowInfo(args.row).rowIndex;
          priceObj = new NumericTextBox({
            value: args.rowData[args.column.field],
            change: function (args) {
              var totalCostValue = args.value * rowData["UnitsInStock"];
              grid.updateCell(rowIndex, "TotalCost", totalCostValue);
            },
          });
          priceObj.appendTo(priceElem);
        },
      },
      stockParams: {
        create: () => {
          stockElem = document.createElement("input");
          return stockElem;
        },
        read: () => {
          return stockObj.value;
        },
        destroy: () => {
          stockObj.destroy();
        },
        write: (args) => {
          grid = new getComponent("Grid1", "grid");
          var rowData = args.rowData;
          var rowIndex = grid.getRowInfo(args.row).rowIndex;
          stockObj = new NumericTextBox({
            value: args.rowData[args.column.field],
            change: function (args) {
              var totalCostValue = args.value * rowData["UnitPrice"];
              grid.updateCell(rowIndex, "TotalCost", totalCostValue);
            },
          });
          stockObj.appendTo(stockElem);
        },
      },
    };
  },
  methods: {
    cellEdit: function (args) {
      if (args.columnName === "TotalCost") {
        args.cancel = true;
      }
    },
  },
  provide: {
    grid: [Edit, Toolbar],
  },
};
</script>

<style>
 @import "../node_modules/@syncfusion/ej2-vue-grids/styles/material.css";
</style>

Cancel edit based on condition in batch mode

You can prevent the CRUD operations of the Batch edit Grid by using condition in the cellEdit, beforeBatchAdd and beforeBatchDelete events for Edit, Add and Delete actions respectively.

In the below demo, we prevent the CRUD operation based on the Role column value. If the Role Column is Employee, we are unable to edit/delete that row.

<template>
    <div id="app">
        <button v-on:click="btnClick">Grid is Addable</button>
        <ejs-grid :dataSource='data' :editSettings='editSettings' :toolbar='toolbar' :cellEdit="cellEdit" :beforeBatchAdd="beforeBatchAdd" :beforeBatchDelete="beforeBatchDelete" height='240px'>
            <e-columns>
                <e-column field='OrderID' headerText='Order ID' textAlign='Right' :isPrimaryKey='true' width=100></e-column>
                <e-column field='Role' headerText='Role' width=120></e-column>
                <e-column field='Freight' headerText='Freight' textAlign= 'Right' editType= 'numericedit' width=120 format= 'C2'></e-column>
                <e-column field='ShipCountry' headerText='Ship Country' editType= 'dropdownedit' width=150></e-column>
            </e-columns>
        </ejs-grid>
    </div>
</template>
<script>
import Vue from "vue";
import { GridPlugin, Page, Toolbar, Edit } from "@syncfusion/ej2-vue-grids";
import { employeeData } from './datasource.js';

Vue.use(GridPlugin);

export default {
  data() {
    return {
      data: employeeData,
      editSettings: { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Batch' },
      toolbar: ['Add', 'Edit', 'Delete', 'Update', 'Cancel'],
      isAddable: true,
    };
  },
  
  methods: {
    cellEdit: function (args) {
      if (args.rowData["Role"] === "Employee") {
        args.cancel = true;
      }
    },
    beforeBatchAdd: function (args) {
      if (!this.isAddable) {
        args.cancel = true;
      }
    },
    beforeBatchDelete: function (args) {
      if (args.rowData["Role"] === "Employee") {
        args.cancel = true;
      }
    },
    btnClick: function (args) {
      args.target.innerText === "Grid is Addable" ? (args.target.innerText = "Grid is Not Addable") : (args.target.innerText = "Grid is Addable");
      this.isAddable = !this.isAddable;
    },
  },
  provide: {
    grid: [Page, Edit, Toolbar]
  }
}
</script>
<style>
 @import "../node_modules/@syncfusion/ej2-vue-grids/styles/material.css";
</style>

Confirmation dialog

By default, grid will show the confirm dialog when saving or cancelling or performing any actions like filtering, sorting, etc.

<template>
    <div id="app">
        <ejs-grid :dataSource='data' :editSettings='editSettings' :toolbar='toolbar' height='273px'>
            <e-columns>
                <e-column field='OrderID' headerText='Order ID' textAlign='Right' :isPrimaryKey='true' width=100></e-column>
                <e-column field='CustomerID' headerText='Customer ID' width=120></e-column>
                <e-column field='Freight' headerText='Freight' textAlign= 'Right' editType= 'numericedit' width=120 format= 'C2'></e-column>
                <e-column field='ShipCountry' headerText='Ship Country' editType= 'dropdownedit' width=150></e-column>
            </e-columns>
        </ejs-grid>
    </div>
</template>
<script>
import Vue from "vue";
import { GridPlugin, Page, Toolbar, Edit } from "@syncfusion/ej2-vue-grids";
import { data } from './datasource.js';

Vue.use(GridPlugin);

export default {
  data() {
    return {
      data: data,
      editSettings: { showConfirmDialog: true, showDeleteConfirmDialog: true, allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Batch' },
      toolbar: ['Add', 'Edit', 'Delete', 'Update', 'Cancel']
    };
  },
  provide: {
    grid: [Page, Edit, Toolbar]
  }
}
</script>
<style>
 @import "../node_modules/@syncfusion/ej2-vue-grids/styles/material.css";
</style>

How to make editing in single click and arrow keys

When using batch mode, the TAB key allows you to edit or move to the next cell or row from the current record by default. Using the grid’s load event, the same functionality can also be achieved by pressing the arrow keys. Additionally, the editCell method of the grid allows for cells to be made editable with a single click.

In the following sample, the load event of the Grid will be used to bind the keydown event handler. When any arrow key is pressed, the editCell method of the Grid will be used to identify the next or previous cell (td) and set it to be editable. Additionally, it is possible to enable editing of a cell with a single click by utilizing the editCell method within the created event of the Grid.

<template>
    <div id="app">
        <ejs-grid ref="grid" id="grid" :dataSource='data' :allowPaging='true' :enableHover='false' :created='created' :load='load' :editSettings='editSettings' :toolbar='toolbar' height='273px'>
            <e-columns>
                <e-column field='OrderID' headerText='Order ID' textAlign='Right' :isPrimaryKey='true' width=100></e-column>
                <e-column field='CustomerID' headerText='Customer ID' width=120></e-column>
                <e-column field='Freight' headerText='Freight' textAlign= 'Right' editType= 'numericedit' width=120 format= 'C2'></e-column>
                <e-column field='OrderDate' headerText='Order Date' textAlign= 'Right' editType= 'datepickeredit' width=120 format= 'yMd'></e-column>
                <e-column field='ShipCountry' headerText='Ship Country' width=150></e-column>
            </e-columns>
        </ejs-grid>
    </div>
</template>
<script>
import Vue from "vue";
import { GridPlugin, Page, Toolbar, Edit } from "@syncfusion/ej2-vue-grids";
import { data } from './datasource.js';
import { isNullOrUndefined } from '@syncfusion/ej2-base';

Vue.use(GridPlugin);

export default {
  data() {
    return {
      data: data,
      editSettings: { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Batch' },
      toolbar: ['Add', 'Edit', 'Delete', 'Update', 'Cancel']
    };
  },
  methods: {
      created: function() {
           let gridInstance = document.getElementById("grid").ej2_instances[0];
           gridInstance.getContentTable().addEventListener('click', (args) => {
              if (args.target.classList.contains('e-rowcell')) {
                   gridInstance.editModule.editCell(parseInt(args.target.getAttribute('index')),
                   gridInstance.getColumnByIndex(parseInt(args.target.getAttribute('data-colindex'))).field);
              }
          });
      },
      editACell: function(args) {
          let gridInstance = document.getElementById("grid").ej2_instances[0];
          gridInstance.editModule.editCell(
          parseInt(args.getAttribute('index')),
          gridInstance.getColumnByIndex(parseInt(args.getAttribute('data-colindex'))).field);
      },
      load: function() {
          let gridInstance = document.getElementById("grid").ej2_instances[0];
          gridInstance.element.addEventListener('keydown', (e) => {
          var closesttd = e.target.closest('td');
          if (e.keyCode === 39 && !isNullOrUndefined(closesttd.nextSibling)) {
              this.editACell(closesttd.nextSibling);
          }
          if (e.keyCode === 37 && !isNullOrUndefined(closesttd.previousSibling) &&
            !gridInstance.getColumnByIndex(
                parseInt(closesttd.previousSibling.getAttribute('data-colindex'))).isPrimaryKey)
          {
               this.editACell(closesttd.previousSibling);
          }
          if (e.keyCode === 40 && !isNullOrUndefined(closesttd.closest('tr').nextSibling)) {
            this.editACell(
                closesttd.closest('tr').nextSibling.querySelectorAll('td')[
                parseInt(closesttd.getAttribute('data-colindex'))]);
          }
          if ( e.keyCode === 38 && !isNullOrUndefined(closesttd.closest('tr').previousSibling)) {
            this.editACell(
                closesttd.closest('tr').previousSibling.querySelectorAll('td')[
                 parseInt(closesttd.getAttribute('data-colindex'))]);
          }
          });
      }
  },
  provide: {
    grid: [Page, Edit, Toolbar]
  }
}
</script>
<style>
 @import "../node_modules/@syncfusion/ej2-vue-grids/styles/material.css";
</style>