Batch editing in Angular Grid component
17 Sep 202524 minutes to read
Batch editing is a robust feature in the Grid component that enables simultaneous editing of multiple cells. This functionality allows efficient modification of several cells and the ability to save all changes with a single request to the data source. Batch editing is particularly advantageous when handling large datasets or when multiple cell updates are required.
In batch edit mode, double-clicking a grid cell changes the targeted cell to an editable state. Bulk updates to added, modified, and deleted data can be committed by clicking the toolbar’s Update button or by programmatically invoking the batchSave method.
To activate batch editing mode, set the editSettings.mode property to Batch. This property controls the editing mode of the Grid and enables batch editing capabilities.
The following example demonstrates enabling batch editing in the Angular Grid component:
import { NgModule } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, EditService, ToolbarService, SortService, PageService } from '@syncfusion/ej2-angular-grids'
import { DatePickerAllModule } from '@syncfusion/ej2-angular-calendars'
import { TimePickerModule } from '@syncfusion/ej2-angular-calendars'
import { DropDownListModule } from '@syncfusion/ej2-angular-dropdowns'
import { TextBoxModule } from '@syncfusion/ej2-angular-inputs'
import { MultiSelectModule } from '@syncfusion/ej2-angular-dropdowns'
import { AutoCompleteModule } from '@syncfusion/ej2-angular-dropdowns'
import { Component, OnInit } from '@angular/core';
import { data } from './datasource';
import { EditSettingsModel, ToolbarItems } from '@syncfusion/ej2-angular-grids';
@Component({
imports: [
GridModule,
DatePickerAllModule,
FormsModule,
TimePickerModule,
FormsModule,
TextBoxModule,
MultiSelectModule,
AutoCompleteModule
],
providers: [EditService, ToolbarService, SortService, PageService],
standalone: true,
selector: 'app-root',
template: `<ejs-grid [dataSource]='data' [editSettings]='editSettings'
[toolbar]='toolbar' height='273px'>
<e-columns>
<e-column field='OrderID' headerText='Order ID' [validationRules]='orderIDRules'
textAlign='Right' isPrimaryKey='true' width=100></e-column>
<e-column field='CustomerID' headerText='Customer ID'
[validationRules]='customerIDRules' width=120></e-column>
<e-column field='Freight' headerText='Freight' textAlign= 'Right'
editType= 'numericedit' [validationRules]='freightRules'
width=120 format= 'C2'></e-column>
<e-column field='ShipCountry' headerText='Ship Country'
editType= 'dropdownedit' [validationRules]='shipCountryRules' width=150></e-column>
</e-columns>
</ejs-grid>`
})
export class AppComponent implements OnInit {
public data?: object[];
public editSettings?: EditSettingsModel;
public toolbar?: ToolbarItems[];
public orderIDRules?: Object;
public customerIDRules?: Object;
public freightRules?: Object;
public shipCountryRules?: Object;
ngOnInit(): void {
this.data = data;
this.editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Batch' };
this.toolbar = ['Add','Delete', 'Update', 'Cancel'];
this.orderIDRules = { required: true, number: true };
this.customerIDRules = { required: true };
this.freightRules = { min:1, max:1000 };
this.shipCountryRules = { required: true };
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Automatically update a column based on changes in another column
It is possible to automatically update a column’s value in batch mode based on the edited value of another column. This is beneficial for dynamic calculations, such as updating a computed field in real time as related columns change. The feature leverages the Cell Edit Template in the Grid component.
In this example, the TotalCost column value updates dynamically as changes are made to the UnitPrice and UnitInStock columns during batch editing.
import { NgModule } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, EditService, ToolbarService, SortService, PageService } from '@syncfusion/ej2-angular-grids'
import { DatePickerAllModule } from '@syncfusion/ej2-angular-calendars'
import { TimePickerModule } from '@syncfusion/ej2-angular-calendars'
import { DropDownListModule } from '@syncfusion/ej2-angular-dropdowns'
import { TextBoxModule } from '@syncfusion/ej2-angular-inputs'
import { MultiSelectModule } from '@syncfusion/ej2-angular-dropdowns'
import { AutoCompleteModule } from '@syncfusion/ej2-angular-dropdowns'
import { Component, OnInit, ViewChild } from '@angular/core';
import { productData } from './datasource';
import { EditSettingsModel, ToolbarItems, IEditCell, GridComponent, CellEditArgs
} from '@syncfusion/ej2-angular-grids';
import { ChangeEventArgs, NumericTextBox } from '@syncfusion/ej2-inputs';
@Component({
imports: [
GridModule,
DatePickerAllModule,
FormsModule,
TimePickerModule,
FormsModule,
TextBoxModule,
MultiSelectModule,
AutoCompleteModule
],
providers: [EditService, ToolbarService, SortService, PageService],
standalone: true,
selector: 'app-root',
template: `
<ejs-grid #grid id="grid" [dataSource]="data" [editSettings]="editSettings" [toolbar]="toolbar"
height="273px" (cellEdit)="cellEdit($event)">
<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" [edit]="priceParams" width="150"
format="C2" textAlign="Right"></e-column>
<e-column field="UnitsInStock" headerText="Units In Stock" [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> `
})
export class AppComponent implements OnInit {
@ViewChild('grid')
public grid?: GridComponent;
public data?: Object[];
public editSettings?: EditSettingsModel;
public toolbar?: ToolbarItems[];
public priceParams?: IEditCell;
public stockParams?: IEditCell;
public priceElem?: HTMLElement;
public priceObj?: NumericTextBox;
public stockElem?: HTMLElement;
public stockObj?: NumericTextBox;
ngOnInit(): void {
this.data = productData;
this.editSettings = {
allowEditing: true,
allowAdding: true,
allowDeleting: true,
mode: 'Batch'
};
this.toolbar = ['Add', 'Delete', 'Update', 'Cancel'];
this.priceParams = {
create: () => {
this.priceElem = document.createElement('input');
return this.priceElem;
},
read: () => {
return this.priceObj?.value;
},
destroy: () => {
this.priceObj?.destroy();
},
write: (args: any) => {
var rowData = args.rowData;
var rowIndex = (this.grid as GridComponent).getRowInfo(args.row).rowIndex;
this.priceObj = new NumericTextBox({
value: args.rowData[args.column.field],
change: ((args: ChangeEventArgs) => {
var totalCostValue = (args.value as number) * rowData['UnitsInStock'];
(this.grid as GridComponent).updateCell((rowIndex as number), 'TotalCost', totalCostValue);
}).bind(this)
});
this.priceObj?.appendTo(this.priceElem);
}
};
this.stockParams = {
create: () => {
this.stockElem = document.createElement('input');
return this.stockElem;
},
read: () => {
return (this.stockObj as NumericTextBox).value;
},
destroy: () => {
(this.stockObj as NumericTextBox).destroy();
},
write: (args: any) => {
var rowData = args.rowData;
var rowIndex = (this.grid as GridComponent).getRowInfo(args.row).rowIndex;
this.stockObj = new NumericTextBox({
value: args.rowData[args.column.field],
change: ((args: ChangeEventArgs) => {
var totalCostValue = (args.value as number) * rowData['UnitPrice'];
(this.grid as GridComponent).updateCell((rowIndex as number), 'TotalCost', totalCostValue);
}).bind(this)
});
this.stockObj.appendTo(this.stockElem);
}
};
}
cellEdit(args: CellEditArgs) {
if (args.columnName == 'TotalCost') {
args.cancel = true;
}
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
- The updateCell method enables programmatic updates to cells in batch mode.
Cancel editing based on specific conditions
The Grid component allows canceling CRUD operations (Edit, Add, Delete) for particular rows or cells in batch edit mode based on custom logic. This provides granular control over which rows or cells are editable.
To cancel an edit action, handle the cellEdit event, which triggers when a cell enters edit mode. Within the event handler, specify a condition to determine whether editing is allowed. When the condition is met, setting args.cancel
to true aborts the edit operation.
To cancel adding a new record, use the beforeBatchAdd event, which occurs prior to a record being added to the batch changes. Similarly, use a condition within the handler to decide if the add operation should proceed.
To cancel the delete action, you need to handle the beforeBatchDelete event. This event is triggered before a record is deleted from the batch changes. Within the event handler, you can add a condition to control whether the delete operation should take place or be canceled. If the condition is met, set the args.cancel
property to true to cancel the delete operation.
In the following demonstration, CRUD operations are prevented for rows in which the Role column has the value Admin:
import { NgModule } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, EditService, ToolbarService, SortService, PageService } from '@syncfusion/ej2-angular-grids'
import { DatePickerAllModule } from '@syncfusion/ej2-angular-calendars'
import { TimePickerModule } from '@syncfusion/ej2-angular-calendars'
import { DropDownListModule } from '@syncfusion/ej2-angular-dropdowns'
import { TextBoxModule } from '@syncfusion/ej2-angular-inputs'
import { MultiSelectModule } from '@syncfusion/ej2-angular-dropdowns'
import { AutoCompleteModule } from '@syncfusion/ej2-angular-dropdowns'
import { ButtonModule } from '@syncfusion/ej2-angular-buttons'
import { Component, OnInit } from '@angular/core';
import { data, columnDataType } from './datasource';
import { BeforeBatchAddArgs, BeforeBatchDeleteArgs, CellEditArgs, EditSettingsModel, ToolbarItems } from '@syncfusion/ej2-angular-grids';
@Component({
imports: [
GridModule,
DatePickerAllModule,
FormsModule,
TimePickerModule,
FormsModule,
TextBoxModule,
MultiSelectModule,
AutoCompleteModule,
ButtonModule
],
providers: [EditService, ToolbarService, SortService, PageService],
standalone: true,
selector: 'app-root',
template: `<div style="padding:0px 0px 20px 0px">
<button ejs-button id="sample" (click)="btnClick($event)">Grid is Addable</button>
</div>
<ejs-grid [dataSource]='data' [editSettings]='editSettings' [toolbar]='toolbar' (cellEdit)="cellEdit($event)"
(beforeBatchAdd)="beforeBatchAdd($event)" (beforeBatchDelete)="beforeBatchDelete($event)" height='240px'>
<e-columns>
<e-column field='OrderID' headerText='Order ID' textAlign='Right' [validationRules]='orderIDRules'
isPrimaryKey='true' width=100></e-column>
<e-column field='Role' headerText='Role' [validationRules]='roleRules' width=120></e-column>
<e-column field='Freight' headerText='Freight' textAlign= 'Right'
editType= 'numericedit' width=120 [validationRules]='freightRules' format= 'C2'></e-column>
<e-column field='ShipCountry' headerText='Ship Country' editType= 'dropdownedit' width=150></e-column>
</e-columns>
</ejs-grid>`
})
export class AppComponent implements OnInit {
public data?: object[];
public editSettings?: EditSettingsModel;
public toolbar?: ToolbarItems[];
public isAddable?: boolean = true;
public orderIDRules?: Object;
public roleRules?: Object;
public freightRules?: Object;
ngOnInit(): void {
this.data = data;
this.editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Batch' };
this.toolbar = ['Add', 'Delete', 'Update', 'Cancel'];
this.orderIDRules = { required: true, number: true };
this.roleRules = {required: true };
this.freightRules = { min:1, max:1000 };
}
cellEdit(args: CellEditArgs) {
if ((args.rowData as columnDataType)['Role'] == 'Admin') {
args.cancel = true;
}
}
beforeBatchAdd(args: BeforeBatchAddArgs) {
if (!this.isAddable) {
args.cancel = true;
}
}
beforeBatchDelete(args: BeforeBatchDeleteArgs) {
if ((args.rowData as columnDataType)['Role'] == 'Admin') {
args.cancel = true;
}
}
btnClick(args: MouseEvent) {
(args.target as HTMLElement).innerText == 'GRID IS ADDABLE' ? ((args.target as HTMLElement).innerText = 'Grid is Not Addable') : ((args.target as HTMLElement).innerText = 'Grid is Addable');
this.isAddable = !this.isAddable;
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Adding a new row at the bottom of the grid
The Grid can be configured to add new rows at the bottom of the data set, making it convenient to insert new records at the end. Set the newRowPosition property in editSettings
to Bottom to activate this option.
- When
newRowPosition
is set to Bottom, the TAB key facilitates data entry across cells or rows while in edit mode. Entering data and pressing TAB automatically creates new rows below the current one, allowing efficient entry for multiple records.- When
newRowPosition
is set to Top, a blank row is displayed at the top for data entry. Upon saving, the new record appears at the end of the grid.- If paging is enabled, updating the row causes it to move to the last page, depending on page size. This behavior applies to both local and remote data sources.
- With scrolling enabled, the TAB key allows adding new rows, even beyond the visible portion of the grid.
- The
newRowPosition
property is supported in both Normal and Batch editing modes.
The following example illustrates how to enable the addition of new rows at the bottom of the grid with the newRowPosition
property:
import { NgModule } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, EditService, ToolbarService, SortService, PageService } from '@syncfusion/ej2-angular-grids'
import { DatePickerAllModule } from '@syncfusion/ej2-angular-calendars'
import { TimePickerModule } from '@syncfusion/ej2-angular-calendars'
import { DropDownListModule } from '@syncfusion/ej2-angular-dropdowns'
import { TextBoxModule } from '@syncfusion/ej2-angular-inputs'
import { MultiSelectModule } from '@syncfusion/ej2-angular-dropdowns'
import { AutoCompleteModule } from '@syncfusion/ej2-angular-dropdowns'
import { Component, ViewChild } from '@angular/core';
import { GridComponent, NewRowPosition } from '@syncfusion/ej2-angular-grids';
import { data } from './datasource';
import { ChangeEventArgs } from '@syncfusion/ej2-dropdowns';
@Component({
imports: [
GridModule,
DatePickerAllModule,
FormsModule,
TimePickerModule,
FormsModule,
TextBoxModule,
MultiSelectModule,
AutoCompleteModule,
DropDownListModule
],
providers: [EditService, ToolbarService, SortService, PageService],
standalone: true,
selector: 'app-root',
template: `
<div style="display: flex">
<label style="padding: 30px 17px 0 0;"> Select new row position:</label>
<ejs-dropdownlist style="padding: 26px 0 0 0" index="0" width="100"
[dataSource]="positionData" (change)="changePosition($event)">
</ejs-dropdownlist>
</div>
<div style="padding-top:20px">
<ejs-grid #batchgrid id='Batchgrid' [dataSource]='data' allowPaging='true' [pageSettings]='pageSettings' [editSettings]='editSettings' [toolbar]='toolbar' >
<e-columns>
<e-column field='OrderID' headerText='Order ID' width='120' textAlign='Right' isPrimaryKey='true' [validationRules]='orderIDRules'></e-column>
<e-column field='CustomerID' headerText='Customer ID' width='120' [validationRules]='customerIDRules'></e-column>
<e-column field='Freight' headerText='Freight' width='120' format='C2' textAlign='Right' editType='numericedit' [validationRules]='freightRules'></e-column>
<e-column field='OrderDate' headerText='Order Date' width='130' format='yMd' editType='datepickeredit' textAlign='Right'></e-column>
<e-column field='ShipCountry' headerText='Ship Country' width='150' editType='dropdownedit' [edit]='editparams'></e-column>
</e-columns>
</ejs-grid>
</div>
`,
})
export class AppComponent {
public data?: Object[];
@ViewChild('batchgrid')
public grid?: GridComponent;
public editSettings?: Object;
public toolbar?: string[];
public orderIDRules?: Object;
public customerIDRules?: Object;
public freightRules?: Object;
public editparams?: Object;
public pageSettings?: Object;
public positionData: Object[] = [
{ text: 'Top', value: 'Top' },
{ text: 'Bottom', value: 'Bottom' },
];
public ngOnInit(): void {
this.data = data;
this.editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Batch' };
this.toolbar = ['Add', 'Delete', 'Update', 'Cancel'];
this.orderIDRules = { required: true, number: true };
this.customerIDRules = { required: true };
this.freightRules = { required: true };
this.editparams = { params: { popupHeight: '300px' } };
this.pageSettings = { pageCount: 5 };
}
public changePosition(args: ChangeEventArgs): void {
(this.grid as GridComponent).editSettings.newRowPosition = args.value as NewRowPosition;
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Confirmation dialog
A confirmation dialog provides verification before performing actions such as saving a record or canceling changes, enhancing data integrity by reducing accidental modifications. The Grid features a built-in confirmation dialog to confirm save, cancel, and related actions.
Enable the confirmation dialog by setting editSettings.showConfirmDialog to true in the editSettings
configuration. The default value is true.
editSettings.showConfirmDialog
requireseditSettings.mode
to be set to Batch.- Setting
editSettings.showConfirmDialog
to false disables the confirmation dialog in batch editing mode.- During updates and deletions, a dedicated delete confirmation dialog appears when selecting the delete button or pressing the delete key.
The following example demonstrates enabling or disabling the confirmation dialog using the showConfirmDialog
property:
import { NgModule } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, EditService, ToolbarService, SortService, PageService } from '@syncfusion/ej2-angular-grids'
import { DatePickerAllModule } from '@syncfusion/ej2-angular-calendars'
import { TimePickerModule } from '@syncfusion/ej2-angular-calendars'
import { DropDownListModule } from '@syncfusion/ej2-angular-dropdowns'
import { TextBoxModule } from '@syncfusion/ej2-angular-inputs'
import { MultiSelectModule } from '@syncfusion/ej2-angular-dropdowns'
import { AutoCompleteModule } from '@syncfusion/ej2-angular-dropdowns'
import { SwitchModule } from '@syncfusion/ej2-angular-buttons'
import { Component, OnInit, ViewChild } from '@angular/core';
import { GridComponent, EditSettingsModel, ToolbarItems } from '@syncfusion/ej2-angular-grids';
import { data } from './datasource';
import { ChangeEventArgs } from '@syncfusion/ej2-buttons';
@Component({
imports: [
GridModule,
DatePickerAllModule,
FormsModule,
TimePickerModule,
FormsModule,
TextBoxModule,
MultiSelectModule,
AutoCompleteModule,
SwitchModule
],
providers: [EditService, ToolbarService, SortService, PageService],
standalone: true,
selector: 'app-root',
template: `
<div style="padding: 20px">
<label>Enable/Disable show confirmation dialog</label>
<ejs-switch id="switch" [(checked)]="enableShowConfirmDialog"
(change)="toggleShowConfirmDialog($event)"></ejs-switch>
</div>
<div style="padding: 20px">
<label>Enable/Disable show delete confirmation dialog</label>
<ejs-switch id="switch1" [(checked)]="enableShowDeleteConfirmDialog"
(change)="toggleShowDeleteConfirmDialog($event)"></ejs-switch>
</div>
<ejs-grid #grid [dataSource]="data" [editSettings]="editSettings" [toolbar]="toolbar" height="273px">
<e-columns>
<e-column field="OrderID" headerText="Order ID" textAlign="Right" [validationRules]="orderIDRules"
isPrimaryKey="true" width="100"></e-column>
<e-column field="CustomerID" headerText="Customer ID" [validationRules]="customerIDRules" width="120"></e-column>
<e-column field="Freight" headerText="Freight" textAlign="Right" editType="numericedit" width="120" format="C2"
[validationRules]="freightRules"></e-column>
<e-column field="ShipCountry" headerText="Ship Country" editType="dropdownedit" width="150"></e-column>
</e-columns>
</ejs-grid> `
})
export class AppComponent implements OnInit {
@ViewChild('grid')
public grid?: GridComponent;
public data: object[] = [];
public editSettings: EditSettingsModel = {};
public toolbar: ToolbarItems[] = ['Add', 'Delete', 'Update', 'Cancel'];
public orderIDRules: Object = {};
public customerIDRules: Object = {};
public freightRules: Object = {};
public enableShowConfirmDialog: boolean = true;
public enableShowDeleteConfirmDialog: boolean = false;
ngOnInit(): void {
this.data = data;
this.editSettings = {
allowEditing: true,
allowAdding: true,
allowDeleting: true,
mode: 'Batch'
};
this.orderIDRules = { required: true, number: true };
this.customerIDRules = { required: true };
this.freightRules = { min: 1, max: 1000 };
}
toggleShowConfirmDialog(args:ChangeEventArgs): void {
(this.grid as GridComponent).editSettings.showConfirmDialog = this.enableShowConfirmDialog;
}
toggleShowDeleteConfirmDialog(args:ChangeEventArgs): void {
(this.grid as GridComponent).editSettings.showDeleteConfirmDialog = this.enableShowDeleteConfirmDialog;
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Single-click editing and navigation with arrow keys
The Grid can be configured for single-click cell editing and navigation across cells or rows using arrow keys, streamlining data entry without requiring double-clicks or mouse navigation.
By default, batch edit mode enables the TAB key to move between cells/rows for editing, while the Enter key moves to the adjacent row cell. To enable single-click editing, handle the created event and bind a click event to grid cells that calls the editCell
method on click.
For arrow key navigation, handle the load event and bind a keydown event to the grid element. Respond to arrow key presses by determining the direction and programmatically invoking the editCell
method for the intended cell.
Below is an example showing both single-click editing and arrow key navigation by using the created
and load
events alongside the editCell
method:
import { NgModule } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, EditService, ToolbarService, SortService, PageService } from '@syncfusion/ej2-angular-grids'
import { DatePickerAllModule } from '@syncfusion/ej2-angular-calendars'
import { TimePickerModule } from '@syncfusion/ej2-angular-calendars'
import { DropDownListModule } from '@syncfusion/ej2-angular-dropdowns'
import { TextBoxModule } from '@syncfusion/ej2-angular-inputs'
import { MultiSelectModule } from '@syncfusion/ej2-angular-dropdowns'
import { AutoCompleteModule } from '@syncfusion/ej2-angular-dropdowns'
import { Component, OnInit, ViewChild } from '@angular/core';
import { data } from './datasource';
import { EditSettingsModel, ToolbarItems, GridComponent } from '@syncfusion/ej2-angular-grids';
import { isNullOrUndefined } from '@syncfusion/ej2-base';
@Component({
imports: [
GridModule,
DatePickerAllModule,
FormsModule,
TimePickerModule,
FormsModule,
TextBoxModule,
MultiSelectModule,
AutoCompleteModule
],
providers: [EditService, ToolbarService, SortService, PageService],
standalone: true,
selector: 'app-root',
template: `<ejs-grid style="padding:70px" #grid id="grid" [dataSource]='data' height='272px' [allowPaging]="true" [enableHover]="false" [editSettings]='editSettings' [toolbar]='toolbar'
(created)="created()" (load)="load()">
<e-columns>
<e-column field='OrderID' headerText='Order ID' textAlign='Right'
isPrimaryKey='true' [validationRules]='orderIDrules' visible='false' width=120></e-column>
<e-column field='CustomerID' [validationRules]='customerIDrules' headerText='Customer ID' width=120></e-column>
<e-column field='Freight' headerText='Freight' [validationRules]='freightrules' format='C2' textAlign='Right' width=150></e-column>
<e-column field='OrderDate' headerText='Order Date' editType='datepickeredit' [validationRules]='orderDaterules' format='yMd' width=150></e-column>
<e-column field='ShipCountry' [validationRules]='shipCountryrules' headerText='Ship Country' width=150></e-column>
</e-columns>
</ejs-grid>`
})
export class AppComponent implements OnInit {
public data?: object[];
public editSettings?: EditSettingsModel;
public toolbar?: ToolbarItems[];
@ViewChild('grid')
public grid?: GridComponent;
public orderIDrules?: Object;
public customerIDrules?: Object;
public freightrules?: Object;
public shipCountryrules?: Object;
public orderDaterules?: Object;
ngOnInit(): void {
this.data = data;
this.editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Batch' },
this.toolbar = ['Add', 'Delete', 'Update', 'Cancel'];
this.orderIDrules = { required: true, number: true };
this.customerIDrules = { required: true };
this.freightrules = { min: 1, max: 1000 };
this.shipCountryrules = { required: true };
this.orderDaterules = { required: true };
}
created = () => {
(this.grid as GridComponent).getContentTable().addEventListener('click', (args) => {
if ((args.target as HTMLElement).classList.contains('e-rowcell')) {
(this.grid as GridComponent).editModule.editCell(parseInt(((args.target as HTMLElement).getAttribute('index') as string)),
(this.grid as GridComponent).getColumnByIndex(parseInt((args.target as HTMLElement).getAttribute('aria-colindex') as string) - 1).field);
}
});
};
load = () => {
(this.grid as GridComponent).element.addEventListener('keydown', (e) => {
var closesttd = (e.target as HTMLElement).closest('td');
if (e.keyCode === 39 && !isNullOrUndefined(((closesttd as HTMLTableCellElement).nextSibling as HTMLElement))) {
this.editACell(((closesttd as HTMLTableCellElement).nextSibling as HTMLElement));
}
if (e.keyCode === 37 && !isNullOrUndefined(((closesttd as HTMLTableCellElement).previousSibling as HTMLElement)) &&
!(this.grid as GridComponent).getColumnByIndex(
parseInt((((closesttd as HTMLTableCellElement).previousSibling as HTMLElement).getAttribute('aria-colindex') as string)) - 1).isPrimaryKey) {
this.editACell(((closesttd as HTMLTableCellElement).previousSibling as HTMLElement));
}
if (e.keyCode === 40 && !isNullOrUndefined((((closesttd as HTMLTableCellElement).closest('tr') as HTMLTableRowElement).nextSibling as HTMLElement))) {
this.editACell(
(((closesttd as HTMLTableCellElement).closest('tr') as HTMLTableRowElement).nextSibling as HTMLElement).querySelectorAll('td')[
parseInt(((closesttd as HTMLTableCellElement).getAttribute('aria-colindex') as string)) - 1]);
}
if (e.keyCode === 38 && !isNullOrUndefined((((closesttd as HTMLTableCellElement).closest('tr') as HTMLTableRowElement).previousSibling as ChildNode))) {
this.editACell(
(((closesttd as HTMLTableCellElement).closest('tr') as HTMLTableRowElement).previousSibling as HTMLElement).querySelectorAll('td')[
parseInt(((closesttd as HTMLTableCellElement).getAttribute('aria-colindex') as string)) - 1]);
}
});
};
public editACell(args: HTMLElement) {
(this.grid as GridComponent).editModule.editCell(
parseInt((args.getAttribute('index') as string)),
(this.grid as GridComponent).getColumnByIndex(parseInt(args.getAttribute('aria-colindex') as string) - 1).field);
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Disable editing for specific cells
Editing can be restricted for designated cells based on custom criteria, enhancing data integrity by preventing changes to read-only, calculated, or protected information.
To disable editing for specific cells in batch mode, utilize the cellEdit event in the grid. By setting args.cancel to true within the event handler, editing is prevented for the target cell.
For example, the following illustrates disabling editing for cells with the value France using the cellEdit
event:
import { NgModule } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, EditService, ToolbarService, SortService, PageService } from '@syncfusion/ej2-angular-grids'
import { DatePickerAllModule } from '@syncfusion/ej2-angular-calendars'
import { TimePickerModule } from '@syncfusion/ej2-angular-calendars'
import { DropDownListModule } from '@syncfusion/ej2-angular-dropdowns'
import { TextBoxModule } from '@syncfusion/ej2-angular-inputs'
import { MultiSelectModule } from '@syncfusion/ej2-angular-dropdowns'
import { AutoCompleteModule } from '@syncfusion/ej2-angular-dropdowns'
import { Component, OnInit } from '@angular/core';
import { data } from './datasource';
import { EditSettingsModel, ToolbarItems, CellEditArgs } from '@syncfusion/ej2-angular-grids';
@Component({
imports: [
GridModule,
DatePickerAllModule,
FormsModule,
TimePickerModule,
FormsModule,
TextBoxModule,
MultiSelectModule,
AutoCompleteModule
],
providers: [EditService, ToolbarService, SortService, PageService],
standalone: true,
selector: 'app-root',
template: `<ejs-grid [dataSource]='data' [editSettings]='editSettings'
[toolbar]='toolbar' (cellEdit)="cellEdit($event)" height='273px'>
<e-columns>
<e-column field='OrderID' headerText='Order ID' [validationRules]='orderIDRules'
textAlign='Right' isPrimaryKey='true' width=100></e-column>
<e-column field='CustomerID' headerText='Customer ID' [validationRules]='customerIDRules'
width=120></e-column>
<e-column field='Freight' headerText='Freight' textAlign= 'Right'
editType= 'numericedit' [validationRules]='freightRules' width=120 format= 'C2'></e-column>
<e-column field='ShipCountry' headerText='Ship Country' editType= 'dropdownedit'
width=150></e-column>
</e-columns>
</ejs-grid>`
})
export class AppComponent implements OnInit {
public data?: object[];
public editSettings?: EditSettingsModel;
public toolbar?: ToolbarItems[];
public orderIDRules?: object;
public customerIDRules?: object;
public freightRules?: Object;
ngOnInit(): void {
this.data = data;
this.editSettings = { allowAdding: true, allowEditing: true,allowDeleting:true, mode: 'Batch' };
this.toolbar = ['Add','Delete', 'Update', 'Cancel'];
this.orderIDRules = { required: true };
this.customerIDRules = { required: true };
this.freightRules = { min:1, max:1000 };
}
cellEdit(args: CellEditArgs) {
if (args.value === 'France') {
args.cancel = true;
}
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Immediate save or update of changes
The Grid enables immediate saving or updating of batch mode changes, removing the necessity for a separate Save button. This supports efficient data editing workflows and instant feedback upon cell modification. The cellSaved event, in conjunction with the batchSave method, facilitates this approach.
By default, invoking the batchSave
method displays a confirmation dialog. This dialog is used to verify the correctness of the changes being saved or canceled.
The cellSaved
event triggers after saving a cell, allowing execution of custom logic upon cell save or update.
The batchSave
method, provided by the grid’s edit service, commits all added, edited, and deleted records in batch mode.
- To bypass the confirmation dialog when using
batchSave
, seteditSettings.showConfirmDialog
to false. Note thateditSettings.mode
must be configured as Batch for this property to take effect. This combination enables immediate persistence of changes without confirmation.
The following example demonstrates immediate saving or updating using the cellSaved
event and the batchSave
method:
import { NgModule } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, EditService, ToolbarService, SortService, PageService } from '@syncfusion/ej2-angular-grids'
import { DatePickerAllModule } from '@syncfusion/ej2-angular-calendars'
import { TimePickerModule } from '@syncfusion/ej2-angular-calendars'
import { DropDownListModule } from '@syncfusion/ej2-angular-dropdowns'
import { TextBoxModule } from '@syncfusion/ej2-angular-inputs'
import { MultiSelectModule } from '@syncfusion/ej2-angular-dropdowns'
import { AutoCompleteModule } from '@syncfusion/ej2-angular-dropdowns'
import { Component, ViewChild, OnInit } from '@angular/core';
import { data } from './datasource';
import { CellSaveArgs,GridComponent } from '@syncfusion/ej2-angular-grids';
@Component({
imports: [
GridModule,
DatePickerAllModule,
FormsModule,
TimePickerModule,
FormsModule,
TextBoxModule,
MultiSelectModule,
AutoCompleteModule
],
providers: [EditService, ToolbarService, SortService, PageService],
standalone: true,
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent implements OnInit {
@ViewChild('normalgrid')
public grid?: GridComponent;
public data?: Object[];
public editSettings?: Object;
public toolbar?: string[];
public orderIDRules?: Object;
public customerIDRules?: Object;
public freightRules?: Object;
public editparams?: Object;
public pageSettings?: Object;
public formatoptions?: Object;
public ngOnInit(): void {
this.data = data.slice(0, 15);
this.editSettings = {
allowEditing: true,
allowAdding: true,
allowDeleting: true,
showConfirmDialog:false,
mode: 'Batch',
};
this.toolbar = ['Add', 'Delete'];
this.orderIDRules = { required: true, number: true };
this.customerIDRules = { required: true };
this.freightRules = { required: true };
this.editparams = { params: { popupHeight: '300px' } };
this.pageSettings = { pageCount: 5 };
this.formatoptions = { type: 'dateTime', format: 'M/d/y hh:mm a' };
}
save(args: CellSaveArgs) {
this.grid?.editModule.batchSave();
}
}
<div class="control-section" style="padding:70px">
<div class="col-lg-9">
<ejs-grid #normalgrid id="Normalgrid" [dataSource]="data" allowPaging="true" [pageSettings]="pageSettings"
[editSettings]="editSettings" [toolbar]="toolbar" (cellSaved)="save($event)">
<e-columns>
<e-column field="OrderID" headerText="Order ID" width="140" textAlign="Right" isPrimaryKey="true"
[validationRules]="orderIDRules"></e-column>
<e-column field="CustomerID" headerText="Customer ID" width="140"
[validationRules]="customerIDRules"></e-column>
<e-column field="Freight" headerText="Freight" width="140" format="C2" textAlign="Right"
editType="numericedit" [validationRules]="freightRules"></e-column>
<e-column field="OrderDate" headerText="Order Date" width="120" editType="datetimepickeredit"
[format]="formatoptions" textAlign="Right"></e-column>
<e-column field='ShipCountry' headerText='Ship Country' width='150' editType='dropdownedit'
[edit]='editparams'></e-column>
</e-columns>
</ejs-grid>
</div>
</div>
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));