Dialog editing in Angular Grid component
16 Sep 202524 minutes to read
Dialog editing is a feature in the Grid component that enables editing of the selected row’s data through a dialog window. This approach allows for convenient modification of cell values and saving changes directly to the data source. Dialog editing is especially effective in scenarios where rapid data modification is needed without navigating away from the current context, facilitating efficient updates to multiple fields at once.
To enable dialog editing, set the editSettings.mode property to Dialog. This property specifies the editing mode for the grid, and when set to Dialog, activates the dialog editing feature.
The following example demonstrates how to enable dialog 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' 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 {
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, mode: 'Dialog' };
this.toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
this.orderIDRules = { required: true, number: true };
this.customerIDRules = { required: true };
this.freightRules = { min: 1, max: 1000 };
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Customize the edit dialog
The edit dialog can be customized to change its appearance and behavior based on the type of action performed, such as editing or adding a record. Properties like header text, showCloseIcon, and height can be tailored to specific requirements. Additionally, localization strings can be overridden to provide custom text for dialog buttons and elements.
To customize the edit dialog, handle the actionComplete event in the Grid component. Use the requestType parameter within the event handler to identify the current action (such as beginEdit for editing or add for record creation), and apply desired customizations accordingly.
Refer to the Grid Default text list for localization options.
The following example demonstrates how to customize the edit dialog using the actionComplete 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 { L10n } from '@syncfusion/ej2-base';
import { Component, OnInit } from '@angular/core';
import { data, columnDataType } from './datasource';
import { EditEventArgs, EditSettingsModel, ToolbarItems } from '@syncfusion/ej2-angular-grids';
L10n.load({
'en-US': {
grid: {
'SaveButton': 'Submit',
'CancelButton': 'Discard'
}
}
});
@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'
(actionComplete)="actionComplete($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' [validationRules]='customerIDRules' headerText='Customer ID' width=120></e-column>
<e-column field='Freight' [validationRules]='freightRules' 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 {
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, mode: 'Dialog' };
this.toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
this.orderIDRules = { required: true, number: true };
this.customerIDRules = { required: true };
this.freightRules = { min: 1, max: 1000 };
}
actionComplete(args: EditEventArgs) {
if ((args.requestType === 'beginEdit' || args.requestType === 'add')) {
const dialog = (args as any).dialog;
dialog.showCloseIcon = false;
dialog.height = 300;
dialog.width = 300;
// change the header of the dialog
dialog.header = args.requestType === 'beginEdit' ? 'Edit Record of ' + (args.rowData as columnDataType)['CustomerID'] : 'New Customer';
}
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));The Grid’s add or edit dialog element applies a max-height property that is calculated based on the available window height. For typical screens (1920 x 1080), the dialog’s maximum height can be set up to 658px.
Show or hide columns in dialog editing
The grid component supports dynamic show or hide functionality for columns within the dialog editing interface. This flexibility allows selective visibility based on the editing context—such as displaying certain columns only during add or edit operations. To achieve this, handle the actionBegin event in the Grid.
The actionBegin event triggers with every grid action (edit, add, delete, etc.). Within the event handler, evaluate the requestType property to determine the context (beginEdit or add, for example) and then set the column.visible property on targeted columns to control their visibility. Reset these properties after saving as needed.
In this example, the CustomerID column is initially hidden, and the ShipCountry column is visible. When entering edit mode, CustomerID becomes visible and ShipCountry is hidden:
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, Column, SaveEventArgs, EditEventArgs } 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 #grid [dataSource]='data' [editSettings]='editSettings' [toolbar]='toolbar' (actionBegin)="actionBegin($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' [validationRules]='customerIDRules'
headerText='Customer ID' [visible]='false' 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[];
@ViewChild('grid') grid?: GridComponent;
public orderIDRules?: Object;
public customerIDRules?: Object;
public freightRules?: Object;
ngOnInit(): void {
this.data = data;
this.editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Dialog' };
this.toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
this.orderIDRules = { required: true, number: true };
this.customerIDRules = { required: true };
this.freightRules = { min: 1, max: 1000 };
}
actionBegin(args: EditEventArgs) {
if (args.requestType === 'beginEdit') {
for (const cols of (this.grid as GridComponent).columns) {
if ((cols as Column).field === 'CustomerID') {
(cols as Column).visible = true;
} else if ((cols as Column).field === 'ShipCountry') {
(cols as Column).visible = false;
}
}
}
else if (args.requestType === 'add') {
for (const cols of (this.grid as GridComponent).columns) {
if ((cols as Column).field === 'CustomerID') {
(cols as Column).visible = true;
}
}
}
else if (args.requestType === 'save') {
for (const cols of (this.grid as GridComponent).columns) {
if ((cols as Column).field === 'CustomerID') {
(cols as Column).visible = false;
} else if ((cols as Column).field === 'ShipCountry') {
(cols as Column).visible = true;
}
}
}
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Wizard-like dialog editing
Wizard-like dialog editing enables step-by-step form entry within the Grid, segmenting complex forms into manageable sections. This structured approach guides users efficiently through the data entry process and improves accuracy in scenarios requiring multiple input stages.
To implement wizard-like dialog editing, use the dialog template feature. Assign editSettings.mode to Dialog and provide a custom template using the editSettingsTemplate property. This template organizes different fields or steps within the wizard flow.
The example below demonstrates wizard-like dialog editing in the grid using unobtrusive validation:
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, EditService, ToolbarService } from '@syncfusion/ej2-angular-grids'
import { ReactiveFormsModule, FormsModule } from '@angular/forms'
import { CheckBoxAllModule, ButtonModule } from '@syncfusion/ej2-angular-buttons'
import { DropDownListAllModule } from '@syncfusion/ej2-angular-dropdowns'
import { NumericTextBoxModule } from '@syncfusion/ej2-angular-inputs'
import { Component, OnInit, ViewChild } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { data } from './datasource';
import { DataUtil } from '@syncfusion/ej2-data';
import { EditSettingsModel, ToolbarItems, GridComponent, DialogEditEventArgs } from '@syncfusion/ej2-angular-grids';
import { Dialog } from '@syncfusion/ej2-popups';
@Component({
imports: [
CheckBoxAllModule,
GridModule,
ButtonModule,
DropDownListAllModule, ReactiveFormsModule, FormsModule,
NumericTextBoxModule
],
providers: [EditService, ToolbarService],
standalone: true,
selector: 'app-root',
templateUrl: `wizardtemplate.html`
})
export class AppComponent implements OnInit {
public data?: object[];
public editSettings?: EditSettingsModel;
public toolbar?: ToolbarItems[];
public shipCountryDistinctData?: object;
public shipCityDistinctData: object[] = [];
public currentTab = 0;
@ViewChild('grid') grid?: GridComponent;
@ViewChild('orderForm') orderForm?: FormGroup;
ngOnInit(): void {
this.data = data;
this.editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Dialog' };
this.toolbar = ['Add', 'Edit', 'Delete'];
this.shipCountryDistinctData = DataUtil.distinct(data, 'ShipCountry', true);
this.shipCityDistinctData = DataUtil.distinct(data, 'ShipCity', true);
}
actionComplete(args: DialogEditEventArgs) {
if ((args.requestType === 'beginEdit') || (args.requestType === 'add')) {
(args as any).form.ej2_instances[0].rules = {}; // Disable default validation.
(args.dialog as any).element.classList.add('hide-default-buttons');
// Set initial Focus
if (args.requestType === 'beginEdit') {
(args?.form?.elements.namedItem('CustomerID') as HTMLInputElement).focus();
}
this.currentTab = 0;
}
}
saveBtn() {
if (this.orderForm?.valid) {
(this.grid as GridComponent).endEdit();
}
}
nextBtn() {
if (this.orderForm?.valid) {
this.currentTab++;
this.removeFocusFromButton()
}
}
previousBtn() {
if (this.orderForm?.valid) {
this.currentTab--;
this.removeFocusFromButton()
}
}
removeFocusFromButton() {
const nextButton = document.getElementById('btn') as HTMLButtonElement;
if (nextButton) {
nextButton.blur();
}
}
}<ejs-grid #grid [dataSource]="data" allowPaging="true" [editSettings]="editSettings" [toolbar]="toolbar"
(actionComplete)="actionComplete($event)">
<e-columns>
<e-column field="OrderID" headerText="Order ID" width="120" textAlign="Right" isPrimaryKey="true"></e-column>
<e-column field="CustomerID" headerText="Customer Name" width="120"></e-column>
<e-column field="Freight" headerText="Freight" width="120"></e-column>
<e-column field="ShipCity" headerText="Ship City" width="120"></e-column>
<e-column field="ShipCountry" headerText="Ship Country" width="150"></e-column>
<e-column field="Verified" headerText="Verified" width="100" type="boolean" [displayAsCheckBox]="true">
</e-column>
</e-columns>
<ng-template #editSettingsTemplate let-data>
<div ngForm #orderForm="ngForm">
<div id="tab0" class="tab" [hidden]="currentTab !== 0">
<!-- Tab 0 Content -->
<div class="form-row">
<div class="form-group col-md-6">
<div class="e-float-input e-control-wrapper"
[ngClass]="{'e-error': OrderID.invalid && (OrderID.dirty || OrderID.touched)}">
<input [(ngModel)]="data.OrderID" required id="OrderID" name="OrderID" type="text"
[disabled]="!data.isAdd " #OrderID="ngModel">
<span class="e-float-line"></span>
<label class="e-float-text e-label-top" for="OrderID"> Order ID</label>
</div>
<div id="OrderIDError" *ngIf="OrderID.invalid && (OrderID.dirty || OrderID.touched)">
<label class="e-error" for="OrderID" id="OrderID-info" style="display: block;">*Order ID is
required</label>
</div>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<div class="e-float-input e-control-wrapper"
[ngClass]="{'e-error': CustomerID.invalid && (CustomerID.dirty || CustomerID.touched)}">
<input [(ngModel)]="data.CustomerID" required id="CustomerID" name="CustomerID" type="text"
#CustomerID="ngModel">
<span class="e-float-line"></span>
<label class="e-float-text e-label-top" for="CustomerID">Customer Name</label>
</div>
<div id="CustomerIDError" *ngIf="CustomerID.invalid && (CustomerID.dirty || CustomerID.touched)">
<label class="e-error" for="CustomerID" id="CustomerID-info" style="display: block;">*Customer Name
is required</label>
</div>
</div>
</div>
</div>
<div id="tab1" class="tab" [hidden]="currentTab !== 1">
<!-- Tab 2 content -->
<div class="form-row">
<div class="form-group col-md-6">
<div class="e-float-input e-control-wrapper"
[ngClass]="{'e-error': Freight.invalid && (Freight.dirty || Freight.touched)}">
<div>
<label class="e-float-text e-label-top" for="Freight">Freight</label>
</div>
<!-- Use ejs-numerictextbox for numeric input -->
<ejs-numerictextbox style="margin-top:10px" [(ngModel)]="data.Freight" required id="Freight"
name="Freight" #Freight="ngModel" floatLabelType='Always'></ejs-numerictextbox>
</div>
<div id="FreightError" *ngIf="Freight.invalid && (Freight.dirty || Freight.touched)">
<label class="e-error" for="Freight" id="Freight-info" style="display: block;">*Freight is
required</label>
</div>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<!-- Use ejs-dropdownlist for ShipCity -->
<ejs-dropdownlist id="ShipCity" name="ShipCity" [(ngModel)]="data.ShipCity"
[dataSource]="shipCityDistinctData" [fields]="{ text: 'ShipCity', value: 'ShipCity' }"
placeholder="Ship City" popupHeight="300px" floatLabelType="Always"></ejs-dropdownlist>
</div>
</div>
</div>
<div id="tab2" class="tab" [hidden]="currentTab !== 2">
<!-- Tab 2 Content -->
<div class="form-row">
<div class="form-group col-md-6">
<ejs-dropdownlist id="ShipCountry" name="ShipCountry" [(ngModel)]="data.ShipCountry"
[dataSource]="shipCountryDistinctData" [fields]="{text: 'ShipCountry', value: 'ShipCountry' }"
placeholder="Ship Country" popupHeight="300px" floatLabelType="Always"></ejs-dropdownlist>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<ejs-checkbox #Verified name="Verified" id="Verified" label="Verified" [checked]="data.Verified">
</ejs-checkbox>
</div>
</div>
</div>
<div id='footer'>
<div style="float: left;">
<button ejs-button type="button" cssClass="e-info e-btn" (click)="previousBtn()" id="btn"
*ngIf="currentTab !== 0">Previous</button>
</div>
<div style="float: right;">
<button ejs-button style="margin-right:10px" type="button" cssClass="e-info e-btn"
(click)="saveBtn()">Save</button>
<button ejs-button type="button" cssClass="e-info e-btn" (click)='nextBtn()' *ngIf="currentTab !== 2" id="btn"
[disabled]="(CustomerID.invalid || OrderID.invalid)">next</button>
</div>
</div>
</div>
</ng-template>
</ejs-grid>import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Customize add/edit dialog footer
The grid component allows customization of the dialog’s footer section, which appears when editing or adding a row. By default, the footer includes Save and Cancel buttons, but you can add custom buttons, modify their appearance, or introduce specialized actions for the dialog.
Customize the dialog’s footer by handling the actionComplete event and utilizing the dialog argument to modify the footer content as desired.
In the following sample, the footer section is customized, and action logic is handled via the dialog argument in the actionComplete 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, ViewChild } from '@angular/core';
import { data } from './datasource';
import { EditSettingsModel, ToolbarItems, GridComponent, EditEventArgs } 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 #grid [dataSource]='data' [editSettings]='editSettings' [toolbar]='toolbar'
(actionComplete)="actionComplete($event)" 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' [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;
@ViewChild('grid') public grid?: GridComponent;
ngOnInit(): void {
this.data = data;
this.editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Dialog' };
this.toolbar = ['Add', 'Edit', 'Delete'];
this.orderIDRules = { required: true, number: true };
this.customerIDRules = { required: true };
this.freightRules = { min: 1, max: 1000 };
}
actionComplete(args: EditEventArgs) {
if (args.requestType === 'beginEdit' || args.requestType === 'add') {
const dialogInstance = (args as any).dialog;
dialogInstance.buttons = [
{
buttonModel: { content: 'Discard', cssClass: 'e-primary custom-button-style' },
click: () => {
this.grid?.editModule.closeEdit();
}
},
{
buttonModel: { content: 'Submit', cssClass: 'e-success custom-button-style' },
click: () => {
this.grid?.editModule.endEdit();
}
}
];
}
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));