Validation in Angular Grid component
17 Sep 202524 minutes to read
Validation is essential for ensuring data integrity in applications. The Syncfusion Angular Grid component provides robust, built-in support for data validation, helping guarantee that data entered or edited in the grid meets predefined criteria and maintaining accuracy across all records.
Column validation
Column validation verifies edited or newly added data against field-specific rules before saving. By applying rules to individual columns, erroneous data is prevented, error messages are shown, and only valid records are committed. Syncfusion Grid leverages the Form Validator component for this purpose. Use the columns.validationRules property to define validation logic for columns.
Example of applying validation rules to a grid column:
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,
DropDownListModule
],
providers: [EditService, ToolbarService, SortService, PageService],
standalone: true,
selector: 'app-root',
template: `<ejs-grid [dataSource]='data' [editSettings]='editSettings'
[toolbar]='toolbar' height='273'>
<e-columns>
<e-column field='OrderID' headerText='Order ID' textAlign='Right'
isPrimaryKey='true' [validationRules]='orderIDRules' width=100>
</e-column>
<e-column field='CustomerID' headerText='Customer ID'
[validationRules]='customerIDRules' 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: 'Normal' };
this.toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
this.orderIDRules = { required: true };
this.customerIDRules = { required: true, minLength: 3 };
this.freightRules = { required: true, 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));Custom validation
Custom validation allows you to implement specific logic for validating column data, beyond built-in rules. Using the Form Validator custom rules, custom validation logic and tailored error messages can be presented to users for any field.
Example: Custom validation for the CustomerID column:
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,
DropDownListModule
],
providers: [EditService, ToolbarService, SortService, PageService],
standalone: true,
selector: 'app-root',
template: `<ejs-grid [dataSource]='data' [editSettings]='editSettings' [toolbar]='toolbar'
height='273'>
<e-columns>
<e-column field='OrderID' headerText='Order ID' textAlign='Right'
isPrimaryKey='true' [validationRules]='orderIDRules' 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;
public customFn: (args: { [key: string]: string }) => boolean = (args: { [key: string]: string }) => {
return args['value'].length >= 5;
}
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 };
this.customerIDRules = { required: true, minLength: [this.customFn, 'Need atleast 5 letters'] };
this.freightRules = { required: true, 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));Custom validation based on dropdown change
Validation rules can be dynamically applied to one column based on the value of another—for example, altering Salary validation based on the selection in a Role dropdown.
Example applying dependent validation between Role and Salary columns:
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 { columnDataType, employeeDetails } from './datasource';
import { EditSettingsModel, ToolbarItems, IEditCell, GridComponent, EditEventArgs } from '@syncfusion/ej2-angular-grids';
import { Query } from '@syncfusion/ej2-data';
import { ChangeEventArgs } from '@syncfusion/ej2-inputs';
let jobRole: { [key: string]: Object }[] = [
{ role: 'TeamLead' },
{ role: 'Manager' },
{ role: 'Engineer' },
{ role: 'Sales' },
{ role: 'Support' },
];
let salaryDetails: { [key: string]: Object }[] = [
{ salary: 6000 },
{ salary: 17000 },
{ salary: 18000 },
{ salary: 26000 },
{ salary: 25000 },
{ salary: 40000 },
{ salary: 35000 },
{ salary: 55000 },
{ salary: 65000 },
];
@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' [editSettings]='editSettings'
[toolbar]='toolbar'(load)="load()" (actionBegin)="actionBegin($event)" >
<e-columns>
<e-column field='EmployeeID' headerText='Employee ID' textAlign='Right'
isPrimaryKey='true' width=120></e-column>
<e-column field='Role' headerText='Role' width=120
editType= 'dropdownedit' [edit]='roleParams'></e-column>
<e-column field='Salary' headerText='Salary' textAlign= 'Right'
editType= 'dropdownedit' width=160 [edit]='salaryParams'></e-column>
<e-column field='Address' headerText='Address' [validationRules]='addressRules'
width=160></e-column>
</e-columns>
</ejs-grid>`
})
export class AppComponent implements OnInit {
public data?: object[];
public rules?: object;
public editSettings?: EditSettingsModel;
public toolbar?: ToolbarItems[];
public roleParams?: IEditCell;
public salaryParams?: IEditCell;
public addressRules?: object;
@ViewChild('grid')
public grid?: GridComponent;
public ngOnInit(): void {
window.role = '';
this.addressRules = { required: true };
this.data = employeeDetails;
this.editSettings = {
allowEditing: true,
allowAdding: true,
allowDeleting: true,
};
this.toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
this.roleParams = {
params: {
query: new Query(),
dataSource: jobRole,
fields: { value: 'role', text: 'role' },
allowFiltering: true,
change: this.valChange.bind(this)
}
};
this.salaryParams = {
params: {
query: new Query(),
dataSource: salaryDetails,
fields: { value: 'salary', text: 'salary' },
allowFiltering: true,
change: this.customFn.bind(this)
}
};
}
public valChange(args: ChangeEventArgs) {
window.role = (args.value?.toString() as string); // Explicitly cast args.value to string
const formObj = (this.grid as GridComponent).editModule.formObj.element['ej2_instances'][0];
switch ( window.role) {
case 'Sales':
formObj.rules['Salary']['required'][1] = 'Please enter valid Sales Salary >=5000 and< 15000';
break;
case 'Support':
formObj.rules['Salary']['required'][1] = 'Please enter valid Support Salary >=15000 and < 19000';
break;
case 'Engineer':
formObj.rules['Salary']['required'][1] = 'Please enter valid Engineer Salary between >=25000 and < 30000';
break;
case 'TeamLead':
formObj.rules['Salary']['required'][1] = 'Please enter valid TeamLead Salary >= 30000 and < 50000';
break;
case 'Manager':
formObj.rules['Salary']['required'][1] = 'Please enter valid Manager Salary >=50000 and < 70000';
break;
}
}
public customFn(args: { value: string }): boolean {
const formObj = (this.grid as GridComponent).editModule.formObj.element['ej2_instances'][0];
let salary = parseInt(args.value)
switch (window.role ) {
case 'Sales':
if ((salary >= 5000) && (salary < 15000))
return true;
else
formObj.rules['Salary']['required'][1] = 'Please enter valid Sales Salary >=5000 and< 15000';
break;
case 'Support':
if ((salary >= 15000 && salary < 19000))
return true;
else
formObj.rules['Salary']['required'][1] = 'Please enter valid Support Salary >=15000 and < 19000';
break;
case 'Engineer':
if ((salary >= 25000 && salary < 30000))
return true;
else
formObj.rules['Salary']['required'][1] = 'Please enter valid Engineer Salary between >=25000 and < 30000';
break;
case 'TeamLead':
if ((salary >= 30000) && (salary < 50000))
return true;
else
formObj.rules['Salary']['required'][1] = 'Please enter valid TeamLead Salary >= 30000 and < 50000';
break;
case 'Manager':
if ((salary >= 50000) && (salary < 70000))
return true;
else
formObj.rules['Salary']['required'][1] = 'Please enter valid Manager Salary >=50000 and < 70000';
break;
}
return false;
}
load(): void {
let column = (this.grid as GridComponent).getColumnByField('Salary');
column.validationRules = {
required: [this.customFn.bind(this),'Please enter valid salary'],
};
}
actionBegin(args: EditEventArgs) {
window.role = (args.rowData as columnDataType)['Role'];
}
}
declare global {
interface Window {
role: string;
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Custom validation for numeric columns
Custom validation for a numeric column Grid is useful when you want to enforce specific validation rules on numeric values in a column. This allows you to define your own validation logic and display custom error messages when the you enters invalid data.
In the following example, custom validation functions, namely customFn and customFn1, are defined to check the entered numeric value against your validation criteria. Then, the grid column is configured with the appropriate validation settings using the freightRules object, specifying the custom validation functions along with corresponding error messages. Additionally, the change event of the numeric column is bound to the validate method of the form element through the edit params. This enables you to trigger validation and display error messages whenever the you modifies the value in the NumericTextBox.
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import {GridModule, EditService, ToolbarService, PageService, EditEventArgs} from '@syncfusion/ej2-angular-grids';
import { Component, ViewChild } from '@angular/core';
import { data } from './datasource';
@Component({
imports: [ GridModule],
standalone: true,
selector: 'app-root',
template: `
<div class="control-section">
<div class="col-lg-9">
<ejs-grid #normalgrid id='Normalgrid' [dataSource]='data' allowPaging='true' (actionComplete)="onActionComplete($event)" [pageSettings]='pageSettings' [editSettings]='editSettings' [toolbar]='toolbar' (actionComplete)='onActionComplete($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' [edit]='edit'></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>`,
providers: [ToolbarService, EditService, PageService]
})
export class AppComponent {
public data?: Object[];
public editSettings?: Object;
public toolbar?: string[];
public orderIDRules?: Object;
public customerIDRules?: Object;
public freightRules?: Object;
public editparams?: Object;
public edit?: Object;
public pageSettings?: Object;
public formatoptions?: Object;
public formElement?: HTMLFormElement;
public customFn: (args: { [key: string]: number }) => boolean = (args: { [key: string]: number }) => {
return (args['value'] <= 1000);
}
public customFn1: (args: { [key: string]: number}) => boolean = (args: { [key: string]: number }) => {
return (args['value'] >= 1);
}
public ngOnInit(): void {
this.data = data;
this.editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true , newRowPosition: 'Top' };
this.toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
this.orderIDRules = { required: true, number: true };
this.customerIDRules = { required: true };
this.freightRules = {
required: true,
maxLength: [this.customFn, 'Please enter a value less than 1000'],
minLength: [this.customFn1, 'Please enter a value greater than 1']
};
this.editparams = { params: { popupHeight: '300px' } };
this.edit = {params: { change: this.onChange.bind(this)}}
this.pageSettings = { pageCount: 5 };
this.formatoptions = { type: 'dateTime', format: 'M/d/y hh:mm a' };
}
onActionComplete(args: EditEventArgs): void {
if (args.requestType === "beginEdit" || args.requestType === "add") {
this.formElement = args.form;
}
}
onChange(): void {
(this.formElement as HTMLFormElement)['ej2_instances'][0].validate();
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Dynamically add or remove validation rules from the form
Validation rules can be adjusted at runtime based on application logic or user interaction. Use addRules to attach rules or removeRules to detach them, by targeting the input name attribute.
Example: Dynamically toggle required validation with a checkbox selection:
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 { CheckBoxModule } from '@syncfusion/ej2-angular-buttons'
import { Component, OnInit, ViewChild } from '@angular/core';
import { data } from './datasource';
import { EditEventArgs, EditSettingsModel, GridComponent, ToolbarItems } from '@syncfusion/ej2-angular-grids';
import { CheckBoxComponent } from '@syncfusion/ej2-angular-buttons';
@Component({
imports: [
GridModule,
DatePickerAllModule,
FormsModule,
TimePickerModule,
FormsModule,
TextBoxModule,
MultiSelectModule,
AutoCompleteModule,
CheckBoxModule
],
providers: [EditService, ToolbarService, SortService, PageService],
standalone: true,
selector: 'app-root',
template: `<div style='padding:2px 2px 20px 3px'>
<ejs-checkbox #checkbox label="Enable/Disable validation rule for customerID coulumn" [checked]="true"></ejs-checkbox>
</div>
<ejs-grid #grid [dataSource]="data" [editSettings]="editSettings" [toolbar]="toolbar" height="273"
(actionComplete)="actionComplete($event)">
<e-columns>
<e-column field="OrderID" headerText="Order ID" textAlign="Right" isPrimaryKey="true"
[validationRules]="orderIDRules" width="100"></e-column>
<e-column field="CustomerID" headerText="Customer ID" width="120" ></e-column>
<e-column field="Freight" headerText="Freight" textAlign="Right"
[validationRules]="freightRules" 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;
@ViewChild('grid') grid?: GridComponent;
@ViewChild('checkbox') checkbox?: CheckBoxComponent;
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 };
this.freightRules = { min: 1, max: 1000 };
}
actionComplete(args: EditEventArgs) {
const formObj = (this.grid as GridComponent).editModule.formObj;
const customerIDRules = {
required: true,
minLength: [5, 'Customer ID should have a minimum length of 5 characters'],
};
if (args.requestType === 'beginEdit' || args.requestType === 'add') {
if ((this.checkbox as CheckBoxComponent).checked) {
// Add the custom validation rule
formObj.addRules('CustomerID', customerIDRules);
}
}
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));To remove an existing validation rule from an input element, use the removeRules method.
Change the position of validation error messages
The default placement for validation error messages is below the input field. To customize error message position (for example, above or beside the input), implement the customPlacement event.
Example displaying error messages at the top of the input field:
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { Component, ViewChild } from '@angular/core';
import { data } from './datasource';
import { GridModule,EditService, ToolbarService, PageService, getObject, GridComponent, EditEventArgs } from '@syncfusion/ej2-angular-grids';
@Component({
imports: [ GridModule],
providers: [EditService, ToolbarService, SortService, PageService],
standalone: true,
selector: 'app-root',
template: `
<div class="control-section">
<ejs-grid #grid [dataSource]='data' (actionComplete)='onActionComplete($event)' allowPaging='true' [pageSettings]='pageSettings' [editSettings]='editSettings' [toolbar]='toolbar'>
<e-columns>
<e-column field='OrderID' headerText='Order ID' width='120' textAlign='Right' [validationRules]='orderIDRules' isPrimaryKey='true' ></e-column>
<e-column field='CustomerID' headerText='Customer Name' 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='ShipCountry' headerText='Ship Country' width='150' editType='dropdownedit' [validationRules]='countryRules' [edit]='editparams'></e-column>
</e-columns>
</ejs-grid>
</div>`
})
export class AppComponent {
public data?: Object[];
public editSettings?: Object;
public toolbar?: string[];
public orderIDRules?: Object;
public customerIDRules?: Object;
public freightRules?: Object;
public countryRules?: Object;
public pageSettings?: Object;
public editparams?: Object;
@ViewChild('grid', {static: false})
public grid?: GridComponent;
public 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.countryRules = { required: true };
this.freightRules = { required: true };
this.editparams = { params: { popupHeight: '200px' }};
this.pageSettings = { pageCount: 5};
}
public onActionComplete(args:EditEventArgs):void {
if (args.requestType == "beginEdit" || args.requestType == "add") {
var valueError = getObject('valErrorPlacement', (this.grid as GridComponent).editModule).bind((this.grid as GridComponent).editModule);
(this.grid as GridComponent).editModule.formObj.customPlacement = (input, error) => {
valueError(input, error);
var element = document.getElementById(input.name + '_Error');
var tooltipWidth = (element as HTMLElement).offsetWidth;
var inputElement = null;
if (document.querySelector('#' + (this.grid as GridComponent).element.id + input.name)) {
inputElement = document.querySelector('#' +(this.grid as GridComponent).element.id + input.name);
} else if (document.querySelector('#' + input.name)) {
inputElement = document.querySelector('#' + input.name);
}
var inputPosition = ( inputElement as Element).getBoundingClientRect();
var leftPosition = (inputPosition.left - tooltipWidth - 16).toString() + 'px'; //for right side
var topPosition = (inputPosition.top).toString() + 'px';
(element as HTMLElement).style.left = leftPosition;
(element as HTMLElement).style.top = topPosition;
(element as HTMLElement).style.position = 'fixed';
}
}
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Show custom error message for failed CRUD actions
During CRUD operations, errors (such as validation failures or server exceptions) can be handled and presented to users via custom messages. Use the actionFailure event to intercept failures, extract server messages, and display them appropriately in the UI.
Example showing server error feedback in Angular Grid:
import { Component, ViewChild } from '@angular/core';
import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
import { GridComponent, EditSettingsModel, ToolbarItems } from '@syncfusion/ej2-angular-grids';
import { FailureEventArgs } from '@syncfusion/ej2-angular-grids';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
@ViewChild('grid') public grid?: GridComponent;
public data?: DataManager;
public editSettings?: EditSettingsModel;
public toolbar?: ToolbarItems[];
public errorMessage: string = '';
public ngOnInit(): void {
this.data = new DataManager({
url: 'https://localhost:****/api/grid', // Replace with your endpoint.
insertUrl: 'https://localhost:****/api/grid/Insert',
updateUrl:'https://localhost:****/api/grid/Update',
removeUrl: 'https://localhost:****/api/grid/Remove',
adaptor: new UrlAdaptor()
});
this.editSettings = { allowAdding: true, allowDeleting: true, allowEditing: true, mode: 'Normal' };
this.toolbar = ['Add', 'Update', 'Delete', 'Cancel'];
}
public onActionFailure(args: FailureEventArgs): void {
(args as any).error?.[0]?.error?.json().then((data: any) => {
this.errorMessage = data.message; // Assign error message.
}).catch(() => {
this.errorMessage = "Error occurred, but message could not be retrieved.";
});
}
}<div *ngIf="errorMessage" class="error-message">
{{ errorMessage }}
</div>
<div style="padding: 20px 17px 0 0">
<ejs-grid #grid [dataSource]='data' (actionFailure)="onActionFailure($event)" allowPaging="true" height="320" [toolbar]="toolbar" [editSettings]="editSettings">
<e-columns>
<e-column field='OrderID' headerText='Order ID' isPrimaryKey=true textAlign='Right' width='150'></e-column>
<e-column field='CustomerID' headerText='Customer Name' width='150'></e-column>
<e-column field='Freight' headerText='Freight' format="C2" width='150' textAlign='Right'></e-column>s
<e-column field='ShipCity' headerText='ShipCity' width='150'></e-column>
</e-columns>
</ejs-grid>
</div>using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using UrlAdaptor.Server.Models;
using Syncfusion.EJ2.Base;
using Newtonsoft.Json.Linq;
namespace UrlAdaptor.Server.Controllers
{
[ApiController]
public class GridController : Controller
{
/// <summary>
/// Handles the HTTP POST request to retrieve data from the data source based on the DataManagerRequest.
/// Supports filtering,searching, sorting, and paging operations (skip and take).
/// </summary>
/// <param name="DataManagerRequest">Contains the filtering, sorting, and paging options requested by the client.</param>
/// <returns>Returns the filtered,searched, sorted, and paginated data along with the total record count.</returns>
[HttpPost]
[Route("api/[controller]")]
public object Post([FromBody] DataManagerRequest DataManagerRequest) {
// Retrieve data from the data source (e.g., database).
IQueryable<OrdersDetails> DataSource = GetOrderData().AsQueryable();
QueryableOperation queryableOperation = new QueryableOperation(); // Initialize QueryableOperation instance.
// Get the total count of records.
int totalRecordsCount = DataSource.Count();
// Handling paging operation.
if (DataManagerRequest.Skip != 0) {
DataSource = queryableOperation.PerformSkip(DataSource, DataManagerRequest.Skip);
}
if (DataManagerRequest.Take != 0) {
DataSource = queryableOperation.PerformTake(DataSource, DataManagerRequest.Take);
}
// Return data based on the request.
return new { result = DataSource, count = totalRecordsCount };
}
/// <summary>
/// Handles the HTTP GET request to retrieve all order records.
/// </summary>
/// <returns>Returns a list of order details.</returns>
[HttpGet]
[Route("api/[controller]")]
public List<OrdersDetails> GetOrderData() {
var data = OrdersDetails.GetAllRecords().ToList();
return data;
}
/// <summary>
/// Inserts a new data item into the data collection.
/// </summary>
/// <param name="newRecord">It contains the new record detail which is need to be inserted.</param>
/// <returns>Returns void.</returns>
[HttpPost]
[Route("api/[controller]/Insert")]
public IActionResult Insert([FromBody] CRUDModel<OrdersDetails> value) {
if (value == null) {
return BadRequest(new { message = "Invalid data received." });
}
var existingOrder = OrdersDetails.order.FirstOrDefault(or => or.OrderID == value.value.OrderID);
if (existingOrder == null) {
OrdersDetails.order.Insert(0, value.value);
return Ok(new { success = true, message = "Order added successfully.", data = value });
}
else {
return BadRequest(new { success = false, message = "Duplicate values cannot be inserted." });
}
}
/// <summary>
/// Update a existing data item from the data collection.
/// </summary>
/// <param name="Order">It contains the updated record detail which is need to be updated.</param>
/// <returns>Returns void.</returns>
[HttpPost]
[Route("api/[controller]/Update")]
public IActionResult Update([FromBody] CRUDModel<OrdersDetails> Order) {
var updatedOrder = Order.value;
if (updatedOrder.OrderID > 10010 || updatedOrder.OrderID < 10030) {
return BadRequest(new { message = "OrderID must be between 10010 and 10030 to update." });
}
var data = OrdersDetails.GetAllRecords().FirstOrDefault(or => or.OrderID == updatedOrder.OrderID);
// Update the existing record
data.OrderID = updatedOrder.OrderID;
data.CustomerID = updatedOrder.CustomerID;
data.ShipCity = updatedOrder.ShipCity;
data.ShipCountry = updatedOrder.ShipCountry;
return Ok(new { success = true, message = "Order updated successfully." });
}
/// <summary>
/// Remove a specific data item from the data collection.
/// </summary>
/// <param name="value">It contains the specific record detail which is need to be removed.</param>
/// <return>Returns void</return>
[HttpPost]
[Route("api/[controller]/Remove")]
public IActionResult Remove([FromBody] CRUDModel<OrdersDetails> value) {
int orderId = int.Parse(value.key.ToString());
if (orderId > 10031 || orderId < 10045) {
return BadRequest(new { message = "OrderID must be between 10031 and 10045 to delete." });
}
var data = OrdersDetails.GetAllRecords().FirstOrDefault(orderData => orderData.OrderID == orderId);
OrdersDetails.GetAllRecords().Remove(data);
return Ok(new { success = true, message = "Order deleted successfully." });
}
public class CRUDModel<T> where T : class
{
public string? action { get; set; }
public string? keyColumn { get; set; }
public object? key { get; set; }
public T? value { get; set; }
public List<T>? added { get; set; }
public List<T>? changed { get; set; }
public List<T>? deleted { get; set; }
public IDictionary<string, object>? @params { get; set; }
}
}
}namespace UrlAdaptor.Server.Models
{
public class OrdersDetails
{
public static List<OrdersDetails> order = new List<OrdersDetails>();
public OrdersDetails(){}
public OrdersDetails(
int OrderID, string CustomerId, int EmployeeId, double Freight, bool Verified,
DateTime OrderDate, string ShipCity, string ShipName, string ShipCountry,
DateTime ShippedDate, string ShipAddress) {
this.OrderID = OrderID;
this.CustomerID = CustomerId;
this.EmployeeID = EmployeeId;
this.Freight = Freight;
this.ShipCity = ShipCity;
this.Verified = Verified;
this.OrderDate = OrderDate;
this.ShipName = ShipName;
this.ShipCountry = ShipCountry;
this.ShippedDate = ShippedDate;
this.ShipAddress = ShipAddress;
}
public static List<OrdersDetails> GetAllRecords()
{
if (order.Count() == 0)
{
int code = 10000;
for (int i = 1; i < 10; i++)
{
order.Add(new OrdersDetails(code + 1, "ALFKI", i + 0, 2.3 * i, false, new DateTime(1991, 05, 15), "Berlin", "Simons bistro", "Denmark", new DateTime(1996, 7, 16), "Kirchgasse 6"));
order.Add(new OrdersDetails(code + 2, "ANATR", i + 2, 3.3 * i, true, new DateTime(1990, 04, 04), "Madrid", "Queen Cozinha", "Brazil", new DateTime(1996, 9, 11), "Avda. Azteca 123"));
order.Add(new OrdersDetails(code + 3, "ANTON", i + 1, 4.3 * i, true, new DateTime(1957, 11, 30), "Cholchester", "Frankenversand", "Germany", new DateTime(1996, 10, 7), "Carrera 52 con Ave. BolĂvar #65-98 Llano Largo"));
order.Add(new OrdersDetails(code + 4, "BLONP", i + 3, 5.3 * i, false, new DateTime(1930, 10, 22), "Marseille", "Ernst Handel", "Austria", new DateTime(1996, 12, 30), "Magazinweg 7"));
order.Add(new OrdersDetails(code + 5, "BOLID", i + 4, 6.3 * i, true, new DateTime(1953, 02, 18), "Tsawassen", "Hanari Carnes", "Switzerland", new DateTime(1997, 12, 3), "1029 - 12th Ave. S."));
code += 5;
}
}
return order;
}
public int? OrderID { get; set; }
public string? CustomerID { get; set; }
public int? EmployeeID { get; set; }
public double? Freight { get; set; }
public string? ShipCity { get; set; }
public bool? Verified { get; set; }
public DateTime OrderDate { get; set; }
public string? ShipName { get; set; }
public string? ShipCountry { get; set; }
public DateTime ShippedDate { get; set; }
public string? ShipAddress { get; set; }
}
}The following screenshot demonstrates displaying error messages when CRUD operations fail:
