How can I help you?
Edit in Angular Grid Component
19 Mar 202624 minutes to read
The Syncfusion® Angular Grid component includes built-in editing features for creating, reading, updating, and deleting data directly in the grid. This eliminates the need for separate forms and allows data modification within a single interface. The grid editing provides powerful options through multiple edit modes, customizable triggers, and flexible data handling.
Set up editing
Before using editing in the grid, understand that the component needs the EditService module to unlock all editing features. The EditService is a service that powers all create, read, update, and delete operations. Without it, editing features cannot work.
Inject the EditService to the providers array.
import { Component, OnInit } from '@angular/core';
import { GridComponent, EditService, ToolbarService, PageService, SortService } from '@syncfusion/ej2-angular-grids';
@Component({
selector: 'app-root',
providers: [EditService, ToolbarService, PageService, SortService]
template: `
<ejs-grid [dataSource]='data'>
</ejs-grid>`,
})
export class AppComponent {
public data: any[] = [...];
}Enable editing
To enable editing functionality directly within the grid, configure the allowEditing, allowAdding, and allowDeleting properties within the editSettings to true.
| Property | Purpose |
|---|---|
allowEditing |
Enable editing of existing records |
allowAdding |
Enable adding new records |
allowDeleting |
Enable deleting records |
Editing requires a primary key column to support full CRUD functionality. Define the primary key by setting columns.isPrimaryKey to true on the relevant column.
Edit actions can be initiated by double-clicking a row or by selecting a row and clicking the Edit button in the toolbar. Records can be added by clicking the Add button in the toolbar or via an external trigger that invokes the addRecord method. Use Save and Cancel to commit or discard changes from the toolbar during edit mode. Deletion is performed by selecting the target row and clicking the Delete button.
To explore available edit modes and types in Angular Grid, refer to the following video:
import { data } from './datasource';
import { Component, OnInit } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { DatePickerAllModule, TimePickerModule } from '@syncfusion/ej2-angular-calendars';
import { AutoCompleteModule, DropDownListModule, MultiSelectModule } from '@syncfusion/ej2-angular-dropdowns';
import { EditService, EditSettingsModel, GridModule, PageService, SortService, ToolbarItems, ToolbarService } from '@syncfusion/ej2-angular-grids';
import { TextBoxModule } from '@syncfusion/ej2-angular-inputs';
@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' 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 [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 orderIDRules?: Object;
public customerIDRules?: Object;
public freightRules?: Object;
ngOnInit(): void {
this.data = data;
this.orderIDRules = { required: true, number: true };
this.customerIDRules = { required: true };
this.freightRules = { required: true,min:1, max:1000 };
this.editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true, };
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
- If columns.isIdentity is enabled, the column will be treated as read-only when editing or adding records.
- Use
columns.allowEditingset tofalseto disable editing for specific columns.- The
Insertkey adds a new row, and theDeletekey deletes the selected row in the grid.
Toolbar with edit options
The toolbar with edit option feature provides a built-in toolbar that includes items for editing actions. Using the toolbar, users can easily modify, update, or cancel grid data edits.
Configure the toolbar property of the Grid component to enable this feature. The toolbar property defines the items displayed in the grid toolbar. Include relevant items like Edit, Add, Delete, Update, and Cancel within the toolbar property to enable edit options in the toolbar.
The following example demonstrates to enable the toolbar with edit option in the grid:
import { data } from './datasource';
import { Component, OnInit } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { DatePickerAllModule, TimePickerModule } from '@syncfusion/ej2-angular-calendars';
import { AutoCompleteModule, MultiSelectModule } from '@syncfusion/ej2-angular-dropdowns';
import { EditService, EditSettingsModel, GridModule, PageService, SortService, ToolbarItems, ToolbarService } from '@syncfusion/ej2-angular-grids';
import { TextBoxModule } from '@syncfusion/ej2-angular-inputs';
@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' [validationRules]='freightRules' textAlign= 'Right' width=120 format= 'C2'></e-column>
<e-column field='ShipCountry' headerText='Ship Country' [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 };
this.toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
this.orderIDRules = { required: true, number: true };
this.customerIDRules = { required: true };
this.freightRules = {required: true ,number: true };
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));Disable editing for specific columns
The Grid component provides the option to disable editing for specific columns. This is useful when certain columns should remain read-only, such as columns containing calculated values, IDs, or system-generated data.
Static column disabling
To permanently disable editing for a column, set the allowEditing property to false on the column. This prevents editing for that column across all rows:
<e-column field='OrderID' [allowEditing]='false'></e-column>Dynamic column disabling
To disable editing for a column based on application interaction or conditions, use the allowEditing property of the columns object. Set this property to false to prevent editing for that specific column.
The following example demonstrates to disable editing for selected columns dynamically in the Grid.
import { data } from './datasource';
import { Component, ViewChild } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { DatePickerAllModule, TimePickerModule } from '@syncfusion/ej2-angular-calendars';
import { AutoCompleteModule, DropDownListComponent, DropDownListModule, MultiSelectModule } from '@syncfusion/ej2-angular-dropdowns';
import { Column, EditService, GridComponent, GridModule, PageService, SortService, ToolbarService } from '@syncfusion/ej2-angular-grids';
import { TextBoxModule } from '@syncfusion/ej2-angular-inputs';
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',
templateUrl: './app.component.html',
})
export class AppComponent {
public data?: Object[];
@ViewChild('grid') public grid?: GridComponent;
@ViewChild('dropdown') public dropdown?: DropDownListComponent;
public editSettings?: Object;
public toolbar?: string[];
public orderIDRules?: Object;
public customerIDRules?: Object;
public freightRules?: Object;
public editparams?: Object;
public pageSettings?: Object;
public alignmentData: Object[] = [
{ text: 'Order ID', value: 'OrderID' },
{ text: 'Customer ID', value: 'CustomerID' },
{ text: 'Freight', value: 'Freight' },
{ text: 'Order Date', value: 'OrderDate' },
{ text: 'Ship Country', value: 'ShipCountry' },
];
public dropdownFields: Object = { text: 'text', value: 'value' }; // Define fields for the dropdown
public currentColumn?: Column;
public ngOnInit(): void {
this.data = data;
this.editSettings = {
allowEditing: true,
allowAdding: true,
allowDeleting: true,
};
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 changeAlignment(args: ChangeEventArgs): void {
// Reset the allowEditing property of the previously selected column
if (this.currentColumn) {
this.currentColumn.allowEditing = true;
}
// Update the 'allowEditing' property for the selected column
this.currentColumn = this.grid?.getColumnByField((args.value as string)) as Column;
this.currentColumn.allowEditing = false;
}
}<div style="display: flex">
<label style="padding: 30px 17px 0 0;"> Select column to disable editing:</label>
<ejs-dropdownlist #dropdown style="padding: 26px 0 0 0" index="0" width="150"
[dataSource]="alignmentData" [fields]="dropdownFields" (change)="changeAlignment($event)">
</ejs-dropdownlist>
</div>
<div>
<ejs-grid #grid id='Batchgrid' [dataSource]='data' allowPaging='true' [pageSettings]='pageSettings'
[editSettings]='editSettings' [toolbar]='toolbar' height='180px'>
<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>import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
- If isPrimaryKey is enabled, editing is automatically disabled for that column.
- To disable editing for a specific row using the actionBegin event. See example here.
- To disable editing for a particular cell using the cellEdit event. See example here.
Editing template columns
Customizing the editing experience for specific columns is possible by defining an editing template. Use the field property to connect the column with its corresponding data field.
In this example, the “Ship Country” column is rendered with a template:
import { FormsModule } from '@angular/forms';
import { GridModule, EditService, ToolbarService, SortService, PageService } from '@syncfusion/ej2-angular-grids';
import { DatePickerAllModule, TimePickerModule } from '@syncfusion/ej2-angular-calendars';
import { DropDownListModule, MultiSelectModule, AutoCompleteModule };
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' [validationRules]='customerIDRules' headerText='Customer ID' 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>
<ng-template #template let-data>
<a href="#">{{data.ShipCountry}}</a>
</ng-template>
</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 = { allowEditing: true, allowAdding: true, allowDeleting: true };
this.toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
this.orderIDRules = { required: true };
this.freightRules = { min:1, max:1000 };
this.customerIDRules = { required: true };
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Customizing the delete confirmation dialog
By default, the Grid shows a confirmation dialog when attempting to delete a row. The appearance and content of this dialog can be customized to match application requirements. Customization can include changing the dialog header, icons, or button text.
To customize the delete confirmation dialog, utilize the toolbarClick event. This event is triggered when a toolbar action is performed and allows modification of dialog properties.
- Enable the confirmation dialog for deletions by setting showDeleteConfirmDialog to
trueineditSettings.- Refer to the grid Default text documentation for localization options.
The following example demonstrates to customize the delete confirmation dialog using the toolbarClick event.
import { data } from './datasource';
import { Component, ViewChild } from '@angular/core';
import { EditService, GridComponent, GridModule, PageService, SortService, ToolbarService } from '@syncfusion/ej2-angular-grids';
import { ClickEventArgs, Item } from '@syncfusion/ej2-angular-navigations';
import { L10n } from '@syncfusion/ej2-base';
L10n.load({
'en-US': {
grid: {
'OKButton':'YES',
'CancelButton':'Discard' ,
'ConfirmDelete': 'Are you sure you want to delete the selected Record?'
}
}
});
@Component({
imports: [ GridModule],
providers: [EditService, ToolbarService, SortService, PageService],
standalone: true,
selector: 'app-root',
template: `
<ejs-grid #grid [dataSource]="data" [editSettings]="editSettings" [toolbar]="toolbar"
(toolbarClick)="toolbarClick($event)" height='250px'>
<e-columns>
<e-column field="OrderID" headerText="Order ID" isPrimaryKey="true" width="120"></e-column>
<e-column field="CustomerID" headerText="Customer ID" width="150"></e-column>
<e-column field="ShipCountry" headerText="Ship Country" width="120"></e-column>
<e-column field="ShipCity" headerText="Ship City" width="130"></e-column>
</e-columns>
</ejs-grid>
`,
})
export class AppComponent {
@ViewChild('grid')
public grid?: GridComponent;
public data?: Object[];
public editSettings?: Object;
public toolbar?: Object;
public ngOnInit(): void {
this.data = data;
this.editSettings = {
allowEditing: true,
allowAdding: true,
allowDeleting: true,
showDeleteConfirmDialog: true,
};
this.toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
}
toolbarClick(args: ClickEventArgs): void {
if ((args.item as Item).text === 'Delete') {
const dialogObj= ((this.grid as GridComponent).editModule as any).dialogObj ;
dialogObj.header = 'Delete Confirmation Dialog';
dialogObj.showCloseIcon = true;
}
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Update boolean column value with a single click
The grid allows boolean column values to be toggled with a single click in normal editing mode. Use the column template feature to render a CheckBox for direct interaction.
The following example demonstrates to render a CheckBox component as a template in the “Verified” column to enable single-click editing:
import { data } from './datasource';
import { Component, OnInit, ViewChild } from '@angular/core';
import { CheckBoxModule } from '@syncfusion/ej2-angular-buttons';
import { EditService, EditSettingsModel, GridComponent, GridModule, ToolbarItems, ToolbarService } from '@syncfusion/ej2-angular-grids';
@Component({
imports: [ GridModule,CheckBoxModule ],
providers: [EditService, ToolbarService ],
standalone: true,
selector: 'app-root',
template: `
<ejs-grid #grid [dataSource]="data" [editSettings]="editSettings" [toolbar]="toolbar" height="250px">
<e-columns>
<e-column field="OrderID" headerText="Order ID" isPrimaryKey="true" textAlign="Right" width="120" [validationRules]='orderIDRules'></e-column>
<e-column field="CustomerID" headerText="Customer Name" width="120" [validationRules]='customerIDRules'></e-column>
<e-column field="OrderDate" headerText="Order Date" editType="datepickeredit" format="M/d/yy" textAlign="Right" [validationRules]='dateRules' width="130" type="date"></e-column>
<e-column field="Freight" headerText="Freight" format="C2" textAlign="Right" width="90" [validationRules]='freightRules'></e-column>
<e-column field="Verified" headerText="Verified" textAlign="Right" width="90" [validationRules]='verifiedRules'>
<ng-template #template let-data>
<ejs-checkbox [(checked)]="data.Verified" (change)="onVerifiedChange(data)"></ejs-checkbox>
</ng-template>
</e-column>
</e-columns>
</ejs-grid>`
})
export class AppComponent implements OnInit {
@ViewChild('grid')
public grid: GridComponent | undefined;
public data?: object[];
public editSettings?: EditSettingsModel;
public toolbar?: ToolbarItems[];
public orderData?: object|any;
public orderIDRules?: object;
public customerIDRules?: object;
public freightRules?: object;
public dateRules?: object;
public verifiedRules?: object;
ngOnInit(): void {
this.data = data;
this.orderIDRules = { required: true };
this.customerIDRules = { required: true };
this.dateRules= { required: true };
this.verifiedRules= { required: true };
this.freightRules = { required: true, min: 1, max: 1000 };
this.editSettings = {
allowEditing: true,
allowAdding: true,
allowDeleting: true,
};
this.toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
}
public onVerifiedChange(rowData: object | any): void {
const rowIndex = (this.grid as GridComponent).getRowIndexByPrimaryKey(
rowData.OrderID
);
(this.grid as GridComponent).updateRow(rowIndex, rowData);
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Editing enum column values
Enum columns contain predefined list values (enumerated data). Instead of allowing free-form text input, using a dropdown editor ensures data consistency and prevents invalid entries. The editTemplate property enables custom editors for enum data.
The following example demonstrates to render a DropDownList component as an edit template for the “Employee Feedback” column, binding it to a predefined list of enum values:
import { data } from './datasource';
import { Component, OnInit } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { DatePickerAllModule, TimePickerModule } from '@syncfusion/ej2-angular-calendars';
import { AutoCompleteModule, ComboBoxModule, DropDownListModule, MultiSelectModule } from '@syncfusion/ej2-angular-dropdowns';
import { EditService, EditSettingsModel, ForeignKeyService, GridModule, PageService, SaveEventArgs, SortService, ToolbarItems, ToolbarService } from '@syncfusion/ej2-angular-grids';
import { TextBoxModule } from '@syncfusion/ej2-angular-inputs';
@Component({
imports: [
GridModule,
DatePickerAllModule,
FormsModule,
TimePickerModule,
FormsModule,
TextBoxModule,
MultiSelectModule,
AutoCompleteModule,
DropDownListModule,
ComboBoxModule
],
providers: [EditService, ToolbarService, SortService, ForeignKeyService,PageService],
standalone: true,
selector: 'app-root',
template: `<ejs-grid [dataSource]="details" [editSettings]="editSettings" [toolbar]="toolbar" (actionBegin)="actionBegin($event)" height='250px'>
<e-columns>
<e-column field="OrderID" headerText="Order ID" isPrimaryKey="true" textAlign="Right" width="90"></e-column>
<e-column field="CustomerID" headerText="Employee Name" textAlign="Left" width="100"></e-column>
<e-column field="FeedbackDetails" headerText="Employee Feedback" textAlign="Left" width="120">
<ng-template #editTemplate let-data>
<ejs-dropdownlist [(ngModel)]="orderData.FeedbackDetails" [dataSource]="dropDownEnumValue" [fields]="dropdownFields" popupHeight="150px">
</ejs-dropdownlist>
</ng-template>
</e-column>
</e-columns>
</ejs-grid>`
})
export class AppComponent implements OnInit {
public details?: EmployeeDetails[];
public editSettings?: EditSettingsModel;
public toolbar?: ToolbarItems[];
public orderData?: EmployeeDetails | any;
public orderIDRules?: object;
public customerIDRules?: object;
public freightRules?: object;
public dropDownEnumValue: string[] = [];
public dropdownFields: Object = { text: 'FeedbackDetails', value: 'FeedbackDetails' };
ngOnInit(): void {
this.details = data as EmployeeDetails[];
this.orderIDRules = { required: true };
this.freightRules = { required: true, min: 1, max: 1000 };
this.editSettings = {
allowEditing: true,
allowAdding: true,
allowDeleting: true,
};
this.toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
this.dropDownEnumValue = Object.keys(Feedback).filter((key: string) => !isNaN(Number((Feedback as any)[key])));
}
actionBegin(args: SaveEventArgs) {
if (args.requestType === 'beginEdit' || args.requestType === 'add') {
this.orderData = Object.assign({}, args.rowData);
}
if (args.requestType === 'save') {
(args.data as EmployeeDetails)['FeedbackDetails'] = this.orderData['FeedbackDetails'];
}
}
}
export interface EmployeeDetails {
OrderID: number;
CustomerID: string;
FeedbackDetails: Feedback;
}
export enum Feedback {
Positive = 0,
Negative = 1,
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Edit complex columns
Complex columns contain nested data objects (such as “Name.FirstName”). When editing complex data with custom input elements, the binding syntax differs from simple columns. Use the underscore operator (___) instead of the dot operator (.) to correctly bind nested properties in edit templates.
The following example demonstrates to edit complex nested data. The “FirstName” and “LastName” properties (nested under “Name”) are edited using input elements with names defined as “Name__FirstName” and “Name__LastName”:
import { complexData } from './datasource';
import { Component, OnInit } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { DatePickerAllModule, TimePickerModule } from '@syncfusion/ej2-angular-calendars';
import { AutoCompleteModule, DropDownListModule, MultiSelectModule } from '@syncfusion/ej2-angular-dropdowns';
import { EditService, EditSettingsModel, GridModule, PageService, SortService, ToolbarItems, ToolbarService } from '@syncfusion/ej2-angular-grids';
import { TextBoxModule } from '@syncfusion/ej2-angular-inputs';
@Component({
imports: [
GridModule,
DatePickerAllModule,
FormsModule,
TimePickerModule,
FormsModule,
TextBoxModule,
MultiSelectModule,
AutoCompleteModule,
DropDownListModule
],
providers: [EditService, ToolbarService, SortService, PageService],
standalone: true,
selector: 'app-root',
template: `
<ejs-grid #grid [dataSource]="data" height="295px" [editSettings]="editSettings" [toolbar]="toolbar" >
<e-columns>
<e-column field="EmployeeID" headerText="Employee ID" textAlign="Right" width="120"></e-column>
<e-column field="Name.FirstName" headerText="First Name" width="200">
<ng-template #editTemplate let-data>
<input class="e-input" name="Name___FirstName" type="text" id="Name___FirstName" [value]="data.Name.FirstName" />
</ng-template>
</e-column>
<e-column field="Name.LastName" headerText="Last Name" width="200">
<ng-template #editTemplate let-data>
<input class="e-input" type="text" name="Name___LastName" id="Name___LastName" [value]="data.Name.LastName" >
</ng-template>
</e-column>
<e-column field="Title" headerText="Title" width="150" ></e-column>
</e-columns>
</ejs-grid>
`,
})
export class AppComponent implements OnInit {
public data?: object[];
public editSettings?: EditSettingsModel;
public toolbar?: ToolbarItems[];
ngOnInit(): void {
this.data = complexData;
this.editSettings = {
allowEditing: true,
allowAdding: true,
allowDeleting: true,
};
this.toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Editing foreign key columns
The Syncfusion Grid offers a powerful editing feature for foreign key columns, enhancing the default rendering of the DropDownList component during editing. This flexibility is particularly useful for customizing the editor for foreign key columns. By default, the Syncfusion Grid renders the DropDownList component as the editor for foreign key columns during editing. However, this behavior can be enhanced and customized by leveraging the editTemplate property for the column using ng-template. The editTemplate property allows specification of a cell edit template that serves as an editor for a particular column, accepting either a template string or an HTML element ID.
In the following code example, the “Employee Name” is a foreign key column. When editing, the ComboBox component is rendered instead of DropDownList.
import { columnDataType, data, employeeData } from './datasource';
import { Component, OnInit } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { DatePickerAllModule, TimePickerModule } from '@syncfusion/ej2-angular-calendars';
import { AutoCompleteModule, ComboBoxModule, DropDownListModule, MultiSelectModule } from '@syncfusion/ej2-angular-dropdowns';
import { EditService, ForeignKeyService, GridModule, PageService, SortService, ToolbarService, EditSettingsModel,ToolbarItems,SaveEventArgs } from '@syncfusion/ej2-angular-grids';
import { TextBoxModule } from '@syncfusion/ej2-angular-inputs';
@Component({
imports: [
GridModule,
DatePickerAllModule,
FormsModule,
TimePickerModule,
FormsModule,
TextBoxModule,
MultiSelectModule,
AutoCompleteModule,
DropDownListModule,
ComboBoxModule
],
providers: [EditService, ToolbarService, SortService, ForeignKeyService,PageService],
standalone: true,
selector: 'app-root',
template: `
<ejs-grid [dataSource]="data" height="220" [editSettings]="editSettings" [allowPaging]="true" [toolbar]="toolbar" (actionBegin)=" actionBegin($event)">
<e-columns>
<e-column field="OrderID" headerText="Order ID" textAlign="Right" isPrimaryKey="true" width="120"></e-column>
<e-column field="EmployeeID" headerText="Employee Name" foreignKeyValue='FirstName' [dataSource]="employeeData" width="150">
<ng-template #editTemplate let-data>
<ejs-combobox [(value)]="orderData.EmployeeID" [dataSource]="employees" [fields]="comboFields" >
</ejs-combobox>
</ng-template>
</e-column>
<e-column field="OrderDate" headerText="Order Date" format="yMd" type="date" textAlign="Right" width="130"></e-column>
<e-column field="Freight" headerText="Freight" format="C2" textAlign="Right" width="120"></e-column>
</e-columns>
</ejs-grid>`
})
export class AppComponent implements OnInit {
public data?: object[];
public editSettings?: EditSettingsModel;
public toolbar?: ToolbarItems[];
public orderData?: object | any;
public orderIDRules?: object;
public customerIDRules?: object;
public employeeIDRules?: object;
public employees: object[] = [];
public employeeData: Object[] = employeeData;
public comboFields: Object = { text: 'FirstName', value: 'EmployeeID' };
ngOnInit(): void {
this.data = data;
this.orderIDRules = { required: true };
this.customerIDRules = { required: true };
this.employeeIDRules = { required: true };
this.editSettings = {
allowEditing: true,
allowAdding: true,
allowDeleting: true,
};
this.toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
this.employees = [
{ FirstName: 'Nancy', EmployeeID: 1 },
{ FirstName: 'Andrew', EmployeeID: 6 },
{ FirstName: 'Janet', EmployeeID: 3 },
{ FirstName: 'Margaret', EmployeeID: 4 },
{ FirstName: 'Steven', EmployeeID: 5 },
{ FirstName: 'Laura', EmployeeID: 8 }
];
}
actionBegin(args: SaveEventArgs) {
if (args.requestType === 'beginEdit' || args.requestType === 'add') {
this.orderData = Object.assign({}, args.rowData);
}
if (args.requestType === 'save') {
(args.data as columnDataType)['EmployeeID'] = this.orderData['EmployeeID'];
}
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Preventing duplicate rows with custom validation
The Syncfusion Angular Grid enables enforcement of constraints to prevent duplicate rows by customizing the validation logic within the grid setup. This ensures data integrity by restricting duplicate entries in the “Order ID” column.
To prevent adding duplicate rows in the grid, follow these steps:
-
Implement Custom Validation: Define the “orderIdCustomValidation” function to check whether the entered “Order ID” already exists in the dataSource. This allows editing an existing row without triggering a duplicate error.
-
Add Dynamic Validation Rules: Create the “orderIDRules” object to enforce unique “Order ID” values. Dynamically add this rule to the form during the
saveaction. -
Handle Validation in the actionBegin event: In the
actionBeginevent, check if therequestTypeissave. Apply the validation rule before saving and cancel the actionargs.cancel = trueif the validation fails.
For server-side validation to prevent adding duplicate rows, refer to the detailed guidance provided in our knowledge base. To display the Grid’s validation tooltip instead of the alert used in the knowledge base, call the grid.editModule.formObj.validate() method in the Ajax/Fetch success function to show the Grid’s tooltip validation for the server side.
import { data } from './datasource';
import { Component, OnInit, ViewChild } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { EditService, EditSettingsModel, GridComponent, GridModule, PageService, SortService, ToolbarItems, ToolbarService } from '@syncfusion/ej2-angular-grids';
@Component({
imports: [GridModule, FormsModule],
providers: [EditService, ToolbarService, SortService, PageService],
standalone: true,
selector: 'app-root',
template: `<ejs-grid #grid [dataSource]='data' [editSettings]='editSettings' [toolbar]='toolbar' height='273' (actionBegin)="actionBegin($event)">
<e-columns>
<e-column field='OrderID' headerText='Order ID' 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' 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 {
@ViewChild('grid') public grid?: GridComponent;
public data?: object[];
public editSettings?: EditSettingsModel;
public toolbar?: ToolbarItems[];
public orderIDRules?: object;
public customerIDRules?: object;
public orderIdCustomValidation(args: any): boolean {
return (this.grid?.dataSource as Object[]).every((data: any) => {
return data['OrderID'] + '' !== args['value'] || data['OrderID'] === (this.grid as any).editModule.editModule.args.rowData['OrderID']
});
}
public actionBegin(args: any):void {
if (args.requestType === 'save') {
(this.grid as GridComponent).editModule.formObj.addRules('OrderID', this.orderIDRules as object); // Add form validation rules dynamically.
if (!(this.grid as GridComponent).editModule.formObj.validate()) { // Check dynamically added validation rules.
args.cancel = true; // Prevent adding duplicate data action.
}
(this.grid as GridComponent).editModule.formObj.removeRules('OrderID'); // Remove form validation rules dynamically.
}
}
public ngOnInit(): void {
this.data = data;
this.editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Normal' };
this.toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
this.orderIDRules = { required: true, min: [this.orderIdCustomValidation.bind(this), 'The entered value already exists in the column OrderID. Please enter a unique value.'] };
this.customerIDRules = { required: true };
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Performing CRUD actions externally
By default, the grid provides built-in editing through toolbars and inline editing. However, CRUD operations can also be triggered programmatically from external controls (custom buttons, forms, or panels outside the grid). This allows full control over when and how data operations occur.
Using a separate toolbar
To perform CRUD operations externally, use the following methods:
| Method | Purpose |
|---|---|
| addRecord | Add a new record (shows edit form if no data provided) |
| startEdit | Begin editing the selected row |
| deleteRecord | Delete the selected row |
| endEdit | Save changes when grid is in edit state |
| closeEdit | Cancel editing without saving |
The following example demonstrates external CRUD operations with a custom toolbar.
import { data } from './datasource';
import { Component, ViewChild } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { DatePickerAllModule, TimePickerModule } from '@syncfusion/ej2-angular-calendars';
import { AutoCompleteModule, DropDownListModule, MultiSelectModule } from '@syncfusion/ej2-angular-dropdowns';
import { EditService, GridComponent, GridModule, PageService, SortService, ToolbarService } from '@syncfusion/ej2-angular-grids';
import { TextBoxModule } from '@syncfusion/ej2-angular-inputs';
import { ToolbarModule } from '@syncfusion/ej2-angular-navigations';
import { ClickEventArgs } from '@syncfusion/ej2-buttons';
@Component({
imports: [
GridModule,
DatePickerAllModule,
FormsModule,
TimePickerModule,
FormsModule,
TextBoxModule,
MultiSelectModule,
AutoCompleteModule,
ToolbarModule ,
DropDownListModule
],
providers: [EditService, ToolbarService, SortService, PageService],
standalone: true,
selector: 'app-root',
template: `
<div style="display: flex">
<ejs-toolbar (clicked)="onToolbarClick($event)">
<e-items>
<e-item text="Add" id="add"></e-item>
<e-item text="Edit" id="edit"></e-item>
<e-item text="Delete" id="delete"></e-item>
<e-item text="Update" id="update"></e-item>
<e-item text="Cancel" id="cancel"></e-item>
</e-items>
</ejs-toolbar>
</div>
<div >
<ejs-grid #grid id='Batchgrid' [dataSource]='data' allowPaging='true' [pageSettings]='pageSettings'
[editSettings]='editSettings' height='220px'>
<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('grid') public grid?: GridComponent;
public editSettings?: Object;
public orderIDRules?: Object;
public customerIDRules?: Object;
public freightRules?: Object;
public editparams?: Object;
public pageSettings?: Object;
public currentColumn: any;
public ngOnInit(): void {
this.data = data;
this.editSettings = {
allowEditing: true,
allowAdding: true,
allowDeleting: true,
};
this.orderIDRules = { required: true, number: true };
this.customerIDRules = { required: true };
this.freightRules = { required: true };
this.editparams = { params: { popupHeight: '300px' } };
this.pageSettings = { pageCount: 5 };
}
public onToolbarClick(args: ClickEventArgs): void {
switch ((args as any).item.id) {
case 'add':
(this.grid as GridComponent).addRecord();
break;
case 'edit':
(this.grid as GridComponent).startEdit();
break;
case 'delete':
(this.grid as GridComponent).deleteRecord();
break;
case 'update':
(this.grid as GridComponent).endEdit();
break;
case 'cancel':
(this.grid as GridComponent).closeEdit();
break;
}
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Using an external form
Instead of editing data in the grid itself, custom forms can be used to edit selected rows. When a row is selected in the grid, the corresponding data is populated in an external form. Changes made in the external form update the grid data.
The rowSelected event can be used to capture row selection and populate external form fields with the selected row’s data. The following example demonstrates editing using an external form.
import { Component, ViewChild } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ButtonModule } from '@syncfusion/ej2-angular-buttons';
import { DropDownListModule } from '@syncfusion/ej2-angular-dropdowns';
import { EditService, GridComponent, GridModule, PageService, RowSelectEventArgs, SortService, ToolbarService } from '@syncfusion/ej2-angular-grids';
import { NumericTextBoxAllModule, TextBoxModule } from '@syncfusion/ej2-angular-inputs';
import{ data } from "./datasource"
@Component({
imports: [ GridModule, FormsModule, TextBoxModule, ButtonModule, NumericTextBoxAllModule,DropDownListModule],
providers: [EditService, ToolbarService, SortService, PageService],
standalone: true,
selector: 'app-root',
template: `
<div class="row" >
<div class="col-xs-6 col-md-3">
<div>
<div class="form-row">
<div class="form-group col-md-12">
<label for="orderedit">OrderID</label>
<input class="form-control" [(ngModel)]="selectedProduct.OrderID" type="number" disabled />
</div>
</div>
<div class="form-row">
<div class="form-group col-md-12">
<label for="customeredit">CustomerID</label>
<ejs-textbox [(value)]="selectedProduct.CustomerID"></ejs-textbox>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-12">
<label for="freightedit">Frieght</label>
<ejs-numerictextbox [(value)]="selectedProduct.Freight"></ejs-numerictextbox>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-12">
<label for="countryedit">ShipCountry</label>
<ejs-dropdownlist [(value)]="selectedProduct.ShipCountry" [dataSource]="dropdown" [fields]="dropdownFields">
</ejs-dropdownlist>
</div>
</div>
</div>
<button ejs-button id="btn" (click)="save()">Save</button>
</div>
<div class="col-xs-6 col-md-9">
<ejs-grid #grid [dataSource]="orders" height="315" width="500px" (rowSelected)="rowSelectHandler($event)" [editSettings]="editSettings">
<e-columns>
<e-column field="OrderID" headerText="OrderID" isPrimaryKey="true" textAlign="Right" width="120"></e-column>
<e-column field="CustomerID" headerText="CustomerID" textAlign="Right" width="120"></e-column>
<e-column field="Freight" headerText="Freight" textAlign="Right" format="C2" width="120"></e-column>
<e-column field="ShipCountry" headerText="ShipCountry" textAlign="Right" width="120"></e-column>
</e-columns>
</ejs-grid>
</div>
</div>
`,
})
export class AppComponent {
public orders:Object[] = data;
@ViewChild('grid') public grid?:GridComponent;
public dropdown: Object[] = [
{ shipCountry: 'Germany' },
{ shipCountry: 'Brazil' },
{ shipCountry: 'France' },
{ shipCountry: 'Belgium' },
{ shipCountry: 'Switzerland' },
{ shipCountry: 'Venezuela' },
{ shipCountry: 'USA' },
{ shipCountry: 'Mexico' },
{ shipCountry: 'Italy' },
{ shipCountry: 'Sweden' },
{ shipCountry: 'Finland' },
{ shipCountry: 'Spain' },
{ shipCountry: 'Canada' },
{ shipCountry: 'Portugal' },
{ shipCountry: 'Denmark' },
{ shipCountry: 'Austria' },
{ shipCountry: 'UK' },
{ shipCountry: 'Ireland' },
{ shipCountry: 'Norway' },
{ shipCountry: 'Argentina' },
];
public selectedProduct: Order = new Order();
public dropdownFields: Object = { text: 'shipCountry', value: 'shipCountry' };
public editSettings: Object = { allowEditing: true };
save(): void {
const index = (this.grid as GridComponent).getSelectedRowIndexes()[0];
(this.grid as GridComponent).updateRow(index, this.selectedProduct);
}
rowSelectHandler(args: RowSelectEventArgs ): void {
(this as any).selectedProduct = { ...args.data };
}
}
export class Order {
OrderID?: number;
CustomerID?: string;
Freight?: number;
ShipCountry?: string;
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Troubleshooting: Editing works only for the first row
If editing or deleting only works for the first row in the grid, the isPrimaryKey property is likely not configured. The primary key is essential for identifying which row to edit or delete. Without it, the grid cannot distinguish between rows.
Solution: Set isPrimaryKey to true on the column that contains unique identifiers:
<e-column field='OrderID' headerText='Order ID' width='100' isPrimaryKey='true'></e-column>Make a grid column always editable
To keep a column editable at all times, use a column template and handle input via the created event and updateRow method for user input management.
Example: Editable “Freight” column textbox template.
import { data } from './datasource';
import { Component, OnInit, ViewChild } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { DatePickerAllModule, TimePickerModule } from '@syncfusion/ej2-angular-calendars';
import { AutoCompleteModule, MultiSelectModule } from '@syncfusion/ej2-angular-dropdowns';
import { EditService, GridComponent, GridModule, PageService, parentsUntil, SortService, ToolbarService } from '@syncfusion/ej2-angular-grids';
import { TextBoxModule } from '@syncfusion/ej2-angular-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 [dataSource]='data' [editSettings]='editSettings' height='315px' (created)="created()">
<e-columns>
<e-column field='OrderID' headerText='Order ID' textAlign='Right' isPrimaryKey='true' width=120></e-column>
<e-column field='OrderDate' headerText='Order Date' width=130 textAlign='Right' format='yMd'></e-column>
<e-column field='ShipCountry' headerText='Ship Country' width=140></e-column>
<e-column field='Freight' headerText='Receipt Amount' textAlign= 'Right' width=150>
<ng-template #template let-data>
<input id='' value='' class='custemp' type='text' style='width: 100%'>
</ng-template>
</e-column>
</e-columns>
</ejs-grid>`
})
export class AppComponent implements OnInit {
public data?: object[];
@ViewChild('grid') public grid?: GridComponent;
public editSettings?: Object;
ngOnInit(): void {
this.data = data;
}
created() {
(this.grid as GridComponent).element.addEventListener('keyup', function (e) { // Bind the keyup event for the grid.
if ((e.target as HTMLElement).classList.contains('custemp')) { // Based on this condition, you can find whether the target is an input element or not.
var row = parentsUntil(e.target as HTMLElement, 'e-row');
var rowIndex = (row as HTMLFormElement)['rowIndex']; // Get the row index.
var uid = row.getAttribute('data-uid');
var grid = (document.getElementsByClassName('e-grid')[0] as HTMLFormElement)['ej2_instances'][0];
var rowData = grid.getRowObjectFromUID(uid).data; // Get the row data.
rowData.Freight = ((e.target as HTMLFormElement)['value']); // Update the new value for the corresponding column.
grid.updateRow(rowIndex, rowData); // Update the modified value in the row data.
}
});
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));If a template column has an associated
fieldproperty, values from the input will be stored in that field in the data object.
See also
- Cascading DropDownList with Grid Editing
- Tab Inside the Dialog Editing
- Apply animation for Grid Edit dialog in Angular Grid
- CRUD operations using ASP.NET core web api methods in Angular Grid
- How to restrict ArrowUp increase and ArrowDown decrease value in Grid numeric cell in Angular Grid
- How to use DropDownList and Combo-Box in Batch-edit mode of Angular Grid
- How to use CellEditArgs event in Angular Grid
- How to render Grid with add form always in Angular Grid
- How to show the numeric key pad in mobile device when edit the number column in Angular Grid
- How to enable inline editing in Angular 4 Data Grid/Table