Validation in Vue Grid component

27 Mar 202524 minutes to read

Validation is a crucial aspect of data integrity in any application. The Vue Grid component in Syncfusion provides built-in support for easy and effective data validation. This feature ensures that the data entered or modified adheres to predefined rules, preventing errors and guaranteeing the accuracy of the displayed information.

Column validation

Column validation allows you to validate the edited or added row data before saving it. This feature is particularly useful when you need to enforce specific rules or constraints on individual columns to ensure data integrity. By applying validation rules to columns, you can display error messages for invalid fields and prevent the saving of erroneous data. This feature leverages the Form Validator component to perform the validation. You can define validation rules using the columns.validationRules property to specify the criteria for validating column values.

The following code example demonstrates how to define a validation rule for grid column:

<template>
  <div id="app">
    <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' :validationRules='shipCountryRules' editType= 'dropdownedit' width=150></e-column>
      </e-columns>
    </ejs-grid>
  </div>
</template>
<script setup>
import { provide } from "vue";
import { GridComponent as EjsGrid, ColumnDirective as EColumn, ColumnsDirective as EColumns, Page, Toolbar, Edit } from "@syncfusion/ej2-vue-grids";
import { data } from './datasource.js';
const editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Normal' };
const toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
const orderIDRules = { required: true };
const customerIDRules = { required: true, minLength: 3 };
const freightRules = { required: true, min: 1, max: 1000 };
const shipCountryRules={ required: true}
provide('grid', [Page, Edit, Toolbar]);
</script>
<style>
@import "../node_modules/@syncfusion/ej2-base/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-calendars/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-dropdowns/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-inputs/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-navigations/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-popups/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-vue-grids/styles/tailwind.css";
</style>
<template>
  <div id="app">
    <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' :validationRules='shipCountryRules' editType= 'dropdownedit' width=150></e-column>
      </e-columns>
    </ejs-grid>
  </div>
</template>
<script>
import { GridComponent, ColumnsDirective, ColumnDirective, Page, Toolbar, Edit } from "@syncfusion/ej2-vue-grids";
import { data } from './datasource.js';
export default {
name: "App",
components: {
"ejs-grid":GridComponent,
"e-columns":ColumnsDirective,
"e-column":ColumnDirective
},
  data() {
    return {
      data: data,
      editSettings: { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Normal' },
      toolbar: ['Add', 'Edit', 'Delete', 'Update', 'Cancel'],
      orderIDRules: { required: true },
      customerIDRules: { required: true, minLength: 3 },
      freightRules : { required: true, min: 1, max: 1000 },
      shipCountryRules:{ required: true}

    };
  },
  provide: {
    grid: [Page, Edit, Toolbar]
  }
}
</script>
<style>
@import "../node_modules/@syncfusion/ej2-base/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-calendars/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-dropdowns/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-inputs/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-navigations/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-popups/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-vue-grids/styles/tailwind.css";
</style>

Custom validation

The Custom validation feature is used to define and enforce your own validation rules for specific columns in the Grid. This is achieved by leveraging the utilizing the Form Validator custom rules, you can enforce your desired validation logic and display error messages for invalid fields.

In the below demo, custom validation applied for CustomerID column.

<template>
  <div id="app">
    <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' :validationRules='shipCountryRules' editType= 'dropdownedit' width=150></e-column>
      </e-columns>
    </ejs-grid>
  </div>
</template>
<script setup>
import { provide } from "vue";
import { GridComponent as EjsGrid, ColumnDirective as EColumn, ColumnsDirective as EColumns, Page, Toolbar, Edit } from "@syncfusion/ej2-vue-grids";
import { data } from './datasource.js';
const editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Normal' };
const toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
const orderIDRules = { required: true };
const shipCountryRules={required: true};
const freightRules = { required: true, min: 1, max: 1000 };
const customerIDRules = { required: true, minLength: [(args) => { return args['value'].length >= 5; }, 'Need atleast 5 letters'] };
provide('grid', [Page, Edit, Toolbar]);
</script>
<style>
@import "../node_modules/@syncfusion/ej2-base/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-calendars/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-dropdowns/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-inputs/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-navigations/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-popups/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-vue-grids/styles/tailwind.css";
</style>
<template>
  <div id="app">
    <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' :validationRules='shipCountryRules' editType= 'dropdownedit' width=150></e-column>
      </e-columns>
    </ejs-grid>
  </div>
</template>
<script>
import { GridComponent, ColumnsDirective, ColumnDirective, Page, Toolbar, Edit } from "@syncfusion/ej2-vue-grids";
import { data } from './datasource.js';
export default {
name: "App",
components: {
"ejs-grid":GridComponent,
"e-columns":ColumnsDirective,
"e-column":ColumnDirective
},
  data() {
    return {
      data: data,
      editSettings: { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Normal' },
      toolbar: ['Add', 'Edit', 'Delete', 'Update', 'Cancel'],
      orderIDRules: { required: true },
      shipCountryRules:{required: true},
      freightRules : { required: true, min: 1, max: 1000 },
      customerIDRules: { required: true, minLength: [(args) => {return args['value'].length >= 5;}, 'Need atleast 5 letters'] }
    };
  },
  provide: {
    grid: [Page, Edit, Toolbar]
  }
}
</script>
<style>
@import "../node_modules/@syncfusion/ej2-base/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-calendars/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-dropdowns/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-inputs/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-navigations/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-popups/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-vue-grids/styles/tailwind.css";
</style>

Custom validation based on dropdown change

The Custom validation feature in the Grid allows you to apply validation rules and messages to a column based on the value of another column in edit mode. This feature is particularly useful when you need to enforce specific validation criteria that depend on the selection made in a dropdown column.

In the following sample, dropdownlist edit type is used for the Role and Salary columns. A custom validation message is shown in the Salary column based on the value selected in the Role column.

<template>
  <div id="app">
    <ejs-grid ref="grid" :dataSource="dataGrid" :editSettings="editSettings" :toolbar="toolbar" :load="load" :actionBegin="actionBegin">
      <e-columns>
        <e-column field="EmployeeID" headerText="Employee ID" textAlign="Right" isPrimaryKey="true" width="120" :validationRules="employeeIDRules"></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>
  </div>
</template>
<script setup>
import { provide, ref} from "vue";
import { GridComponent as EjsGrid, ColumnDirective as EColumn, ColumnsDirective as EColumns, Page, Toolbar, Edit } from "@syncfusion/ej2-vue-grids";
import { Query } from '@syncfusion/ej2-data';
import { employeeDetails } from './datasource.js';
const jobRole = [
  { role: 'TeamLead' },
  { role: 'Manager' },
  { role: 'Engineer' },
  { role: 'Sales' },
  { role: 'Support' },
];

const salaryDetails = [
  { salary: 6000 },
  { salary: 17000 },
  { salary: 18000 },
  { salary: 26000 },
  { salary: 25000 },
  { salary: 40000 },
  { salary: 35000 },
  { salary: 55000 },
  { salary: 65000 },
];
const grid=ref(null);
const dataGrid= employeeDetails;
const editSettings= { allowEditing: true, allowAdding: true, allowDeleting: true };
const toolbar= ["Add", "Edit", "Delete", "Update", "Cancel"];
const addressRules= { required: true };
const employeeIDRules= { required: true };

const valChange=function(args) {
  window.role = args.value.toString();
  const formObj = grid.value.ej2Instances.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;
  }
};
const roleParams= {
  params: {
    query: new Query(),
    dataSource: jobRole,
    fields: { value: 'role', text: 'role' },
    allowFiltering: true,
    change: valChange,
  }
};
const salaryParams= {
  params: {
    query: new Query(),
    dataSource: salaryDetails,
    fields: { value: 'salary', text: 'salary' },
    allowFiltering: true,
  }
};

const customFn=function(args){
  const formObj = grid.value.ej2Instances.editModule.formObj.element['ej2_instances'][0];
  switch (window.role) {
    case 'Sales':
      if (args.value >= 5000 && args.value < 15000) return true;
        formObj.rules['Salary']['required'][1] = 'Please enter valid Sales Salary >=5000 and < 15000';
        break;
    case 'Support':
      if (args.value >= 15000 && args.value < 19000) return true;
        formObj.rules['Salary']['required'][1] = 'Please enter valid Support Salary >=15000 and < 19000';
      break;
    case 'Engineer':
      if (args.value >= 25000 && args.value < 30000) return true;
        formObj.rules['Salary']['required'][1] = 'Please enter valid Engineer Salary between >=25000 and < 30000';
      break;
    case 'TeamLead':
      if (args.value >= 30000 && args.value < 50000) return true;
        formObj.rules['Salary']['required'][1] = 'Please enter valid TeamLead Salary >= 30000 and < 50000';
      break;
    case 'Manager':
      if (args.value >= 50000 && args.value < 70000) return true;
        formObj.rules['Salary']['required'][1] = 'Please enter valid Manager Salary >=50000 and < 70000';
      break;
  }
    return false;
};
const load=()=> {
      let column = grid.value.getColumnByField('Salary');
      column.validationRules = {
        required: [customFn, 'Please enter valid salary'],
      };
    };
const actionBegin=(args)=> {
      if (args.requestType === 'beginEdit') {
        window.role = args.rowData.Role;
      }
    };
provide('grid', [Page, Edit, Toolbar]);
</script>
<style>
@import "../node_modules/@syncfusion/ej2-base/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-calendars/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-dropdowns/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-inputs/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-navigations/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-popups/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-vue-grids/styles/tailwind.css";
</style>
<template>
  <div id="app">
    <ejs-grid ref="grid" :dataSource="dataGrid" :editSettings="editSettings" :toolbar="toolbar" :load="load" :actionBegin="actionBegin">
      <e-columns>
        <e-column field="EmployeeID" headerText="Employee ID" textAlign="Right" isPrimaryKey="true" width="120" :validationRules="employeeIDRules"></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>
  </div>
</template>
<script>
import { GridComponent, ColumnsDirective, ColumnDirective, Toolbar, Edit } from "@syncfusion/ej2-vue-grids";
import { Query } from '@syncfusion/ej2-data';
import { employeeDetails } from './datasource.js';

const jobRole = [
  { role: 'TeamLead' },
  { role: 'Manager' },
  { role: 'Engineer' },
  { role: 'Sales' },
  { role: 'Support' },
];

const salaryDetails = [
  { salary: 6000 },
  { salary: 17000 },
  { salary: 18000 },
  { salary: 26000 },
  { salary: 25000 },
  { salary: 40000 },
  { salary: 35000 },
  { salary: 55000 },
  { salary: 65000 },
];

export default {
  name: "App",
  components: {
    "ejs-grid": GridComponent,
    "e-columns": ColumnsDirective,
    "e-column": ColumnDirective,
  },
  data() {
    return {
      dataGrid: employeeDetails,
      editSettings: { allowEditing: true, allowAdding: true, allowDeleting: true },
      toolbar: ["Add", "Edit", "Delete", "Update", "Cancel"],
      addressRules: { required: true },
      employeeIDRules: { required: true },
      roleParams: {
        params: {
          query: new Query(),
          dataSource: jobRole,
          fields: { value: 'role', text: 'role' },
          allowFiltering: true,
          change: this.valChange.bind(this),
        },
      },
      salaryParams: {
        params: {
          query: new Query(),
          dataSource: salaryDetails,
          fields: { value: 'salary', text: 'salary' },
          allowFiltering: true,
        },
      }
    };
  },
  methods: {
    valChange(args) {
      window.role = args.value.toString();
      const formObj = this.$refs.grid.ej2Instances.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;
      }
    },
    customFn(args) {
      const formObj = this.$refs.grid.ej2Instances.editModule.formObj.element['ej2_instances'][0];
      switch (window.role) {
        case 'Sales':
          if (args.value >= 5000 && args.value < 15000) return true;
          formObj.rules['Salary']['required'][1] = 'Please enter valid Sales Salary >=5000 and < 15000';
          break;
        case 'Support':
          if (args.value >= 15000 && args.value < 19000) return true;
          formObj.rules['Salary']['required'][1] = 'Please enter valid Support Salary >=15000 and < 19000';
          break;
        case 'Engineer':
          if (args.value >= 25000 && args.value < 30000) return true;
          formObj.rules['Salary']['required'][1] = 'Please enter valid Engineer Salary between >=25000 and < 30000';
          break;
        case 'TeamLead':
          if (args.value >= 30000 && args.value < 50000) return true;
          formObj.rules['Salary']['required'][1] = 'Please enter valid TeamLead Salary >= 30000 and < 50000';
          break;
        case 'Manager':
          if (args.value >= 50000 && args.value < 70000) return true;
          formObj.rules['Salary']['required'][1] = 'Please enter valid Manager Salary >=50000 and < 70000';
          break;
      }
      return false;
    },
    load() {
      let column = this.$refs.grid.ej2Instances.getColumnByField('Salary');
      column.validationRules = {
        required: [this.customFn.bind(this), 'Please enter valid salary'],
      };
    },
    actionBegin(args) {
      if (args.requestType === 'beginEdit') {
        window.role = args.rowData.Role;
      }
    },
  },
  provide() {
    return {
      grid: [Edit, Toolbar],
    };
  }
};
</script>

<style>
@import "../node_modules/@syncfusion/ej2-base/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-calendars/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-dropdowns/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-inputs/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-navigations/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-popups/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-vue-grids/styles/tailwind.css";
</style>

Custom validation for numeric column

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.

<template>
  <div id="app">
    <ejs-grid :dataSource='dataGrid' allowPaging='true' :actionComplete="onActionComplete" :pageSettings='pageSettings' :editSettings='editSettings' :toolbar='toolbar'>
      <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' type="date" width='120' :validationRules='orderDateRules' editType='datetimepickeredit' format='y/m/d' textAlign='Right'></e-column>
        <e-column field='ShipCountry' headerText='Ship Country' width='150' :validationRules='shipCountryRules' editType='dropdownedit' :edit='editparams'></e-column>
      </e-columns>
    </ejs-grid>
  </div>
</template>
<script setup>
import { provide } from "vue";
import { GridComponent as EjsGrid, ColumnDirective as EColumn, ColumnsDirective as EColumns, Page, Toolbar, Edit } from "@syncfusion/ej2-vue-grids";
import { data } from './datasource.js';

let formElement;
const editSettings = {
  allowEditing: true,
  allowAdding: true,
  allowDeleting: true,
  mode: 'Normal',
  newRowPosition: 'Top'
};
const dataGrid=data;
const toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
const orderIDRules = { required: true, number: true };
const shipCountryRules = { required: true };
const orderDateRules = { required: true };
const customerIDRules = { required: true };
const freightRules = {
  required: true,
  maxLength: [(args) => args['value'] <= 1000, 'Please enter a value less than 1000'],
  minLength: [(args) => args['value'] >= 1, 'Please enter a value greater than 1']
};
const editparams = { params: { popupHeight: '300px' } };
const pageSettings = { pageCount: 5 };
const onActionComplete = function(args) {
  if (args.requestType === "beginEdit" || args.requestType === "add") {
    formElement = args.form;
  }
};
const onChange = function() {
  if (formElement) {
    formElement['ej2_instances'][0].validate(); 
  }
};
const edit = { params: { change: onChange } };

provide('grid', [Page, Edit, Toolbar]);
</script>

<style>
@import "../node_modules/@syncfusion/ej2-base/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-calendars/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-dropdowns/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-inputs/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-navigations/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-popups/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-vue-grids/styles/tailwind.css";
</style>
<template>
  <div id="app">
    <ejs-grid  :dataSource='dataGrid' allowPaging='true' :actionComplete="onActionComplete" :pageSettings='pageSettings' :editSettings='editSettings' :toolbar='toolbar'>
      <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' type="date" width='120' :validationRules='orderDateRules' editType='datetimepickeredit' format='y/m/d' textAlign='Right'></e-column>
        <e-column field='ShipCountry' headerText='Ship Country' width='150' :validationRules='shipCountryRules' editType='dropdownedit' :edit='editparams'></e-column>
      </e-columns>
    </ejs-grid>
  </div>
</template>
<script>
import { GridComponent, ColumnsDirective, ColumnDirective, Page, Toolbar, Edit } from "@syncfusion/ej2-vue-grids";
import { data } from './datasource.js';
export default {
name: "App",
components: {
"ejs-grid":GridComponent,
"e-columns":ColumnsDirective,
"e-column":ColumnDirective
},
  data() {
    return {
      dataGrid: data,
      formElement:"",
      editSettings: { allowEditing: true, allowAdding: true, allowDeleting: true, mode: "Normal",newRowPosition: "Top" },
      toolbar: ["Add", "Edit", "Delete", "Update", "Cancel"],
      orderIDRules: { required: true, number: true },
      shipCountryRules: { required: true },
      orderDateRules: { required: true },
      freightRules: {
        required: true,
        maxLength: [
          (args) => args["value"] <= 1000,
          "Please enter a value less than 1000",
        ],
        minLength: [
          (args) => args["value"] >= 1,
          "Please enter a value greater than 1",
        ],
      },
      customerIDRules: { required: true },
      editparams: { params: { popupHeight: "300px" } },
      edit : { params: { change: this.onChange.bind(this) } },
      pageSettings: { pageCount: 5 },
    };
  },

  methods: {
    onActionComplete: function (args) {
      if (args.requestType === "beginEdit" || args.requestType === "add") {
        this.formElement = args.form;
      }
    },
    onChange: function () {
      if (this.formElement) {
        this.formElement["ej2_instances"][0].validate();
      }
    },
  },
  provide: {
    grid: [Page, Edit, Toolbar],
  }
};
</script>
<style>
@import "../node_modules/@syncfusion/ej2-base/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-calendars/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-dropdowns/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-inputs/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-navigations/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-popups/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-vue-grids/styles/tailwind.css";
</style>

Dynamically add or remove validation rules from the form

You can dynamically add or remove validation rules from input elements within a form. This feature is particularly useful when you need to adjust the validation rules based on different scenarios or dynamically changing data.

To add validation rules dynamically to an input element, you can use the addRules method. This method enables you to add validation rules to the corresponding input element based on the name attribute.

The following example to demonstrates how to dynamically add or remove a required validation rule for an input field based on a CheckBox selection:

<template>
  <div id="app">
    <div style='padding:2px 2px 20px 3px'>
      <ejs-checkbox ref="checkbox" label="Enable/Disable validation rule for customerID coulumn" :checked="true"></ejs-checkbox>
    </div>
    <ejs-grid ref="grid" :dataSource="data" :editSettings="editSettings" :toolbar="toolbar" height="273"
    :actionComplete="actionComplete">
      <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" :validationRules="customerIDRules"></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" :validationRules="shipCountryRules">
       </e-column>
      </e-columns>
    </ejs-grid>
  </div>
</template>
<script setup>
import { provide, ref } from "vue";
import { GridComponent as EjsGrid, ColumnDirective as EColumn, ColumnsDirective as EColumns, Page, Toolbar, Edit } from "@syncfusion/ej2-vue-grids";
import { CheckBoxComponent as EjsCheckbox} from "@syncfusion/ej2-vue-buttons";
import { data } from './datasource.js';

const grid = ref(null); 
const checkbox = ref(null); 
const editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Normal' };
const toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
const orderIDRules = { required: true, number: true };
const freightRules = { required: true, min: 1, max: 1000 };
const shipCountryRules = { required: true };

const actionComplete = function(args) {
  const formObj = grid.value.ej2Instances.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 (checkbox.value.ej2Instances.checked) {
      formObj.addRules('CustomerID', customerIDRules);
    } 
  }
};

provide('grid', [Page, Edit, Toolbar]);
</script>
<style>
@import "../node_modules/@syncfusion/ej2-base/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-calendars/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-dropdowns/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-inputs/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-navigations/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-popups/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-vue-grids/styles/tailwind.css";
</style>
<template>
  <div id="app">
    <div style='padding:2px 2px 20px 3px'>
      <ejs-checkbox ref="checkbox" label="Enable/Disable validation rule for customerID coulumn" :checked="true"></ejs-checkbox>
    </div>
    <ejs-grid ref="grid" :dataSource="data" :editSettings="editSettings" :toolbar="toolbar" height="273"
    :actionComplete="actionComplete">
      <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" :validationRules="shipCountryRules">
       </e-column>
      </e-columns>
    </ejs-grid>
  </div>
</template>
<script>
import { GridComponent, ColumnsDirective, ColumnDirective, Page, Toolbar, Edit } from "@syncfusion/ej2-vue-grids";
import { CheckBoxComponent } from "@syncfusion/ej2-vue-buttons";
import { data } from './datasource.js';
export default {
name: "App",
components: {
"ejs-grid":GridComponent,
"e-columns":ColumnsDirective,
"e-column":ColumnDirective,
"ejs-checkbox": CheckBoxComponent
},
  data() {
    return {
      data: data,
      editSettings: { allowEditing: true, allowAdding: true, allowDeleting: true, mode: "Normal" },
      toolbar: ["Add", "Edit", "Delete", "Update", "Cancel"],
      orderIDRules: { required: true, number: true },
      shipCountryRules: { required: true },
      freightRules: { required: true,min: 1, max: 1000},
      customerIDRules: { required: true },
    };
  },
  methods: {
    actionComplete: function (args) {
      const formObj = this.$refs.grid.ej2Instances.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.$refs.checkbox.ej2Instances.checked) {
                formObj.addRules('CustomerID', customerIDRules);
            }
        }
    }
  },
  provide: {
    grid: [Page, Edit, Toolbar],
  }
};
</script>
<style>
@import "../node_modules/@syncfusion/ej2-base/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-calendars/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-dropdowns/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-inputs/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-navigations/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-popups/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-vue-grids/styles/tailwind.css";
</style>

To remove an existing validation rule from an input element, you can use the removeRules method.

Change the position of validation error message

By default, the validation error message in Grid is displayed below the input field. However, you have an option to customize its position and display it in a different location. This feature is particularly useful when you want to align the error message according to your application’s design and layout.

To change the position of the validation error message in Grid, you can utilize the customPlacement event. This event allows you to define a custom logic to position the error message at the desired location.

Here’s an example that demonstrates how to change the position of the validation error message to the top of the input field:

<template>
  <div id="app">
    <ejs-grid ref="grid" :dataSource='dataGrid' :actionComplete='actionComplete' 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>
</template>
<script setup>
import { provide,ref } from "vue";
import { GridComponent as EjsGrid, ColumnDirective as EColumn, ColumnsDirective as EColumns, Page, Toolbar, Edit,getObject } from "@syncfusion/ej2-vue-grids";
import { data } from './datasource.js';

const dataGrid= data;
const grid=ref(null);
const editSettings= { allowEditing: true, allowAdding: true, allowDeleting: true, mode: "Dialog" };
const toolbar= ["Add", "Edit", "Delete", "Update", "Cancel"];
const orderIDRules= { required: true, number: true };
const freightRules= { required: true, min: 1, max: 1000 };
const customerIDRules= { required: true };
const countryRules= { required: true };
const editparams= { params: { popupHeight: '200px' } };
const pageSettings= { pageCount: 5 };

const actionComplete=(args)=> {
  if (args.requestType == "beginEdit" || args.requestType == "add") { 
    let editModule = grid.value.ej2Instances.editModule;
    let valueError = getObject('valErrorPlacement', editModule).bind(editModule);
    grid.value.ej2Instances.editModule.formObj.customPlacement = (input, error) => { 
      valueError(input, error);
      var element = document.getElementById(input.name + '_Error');
      var tooltipWidth = element.offsetWidth;
      var  inputElement = null;
      if (document.querySelector('#' + grid.value.ej2Instances.element.id + input.name)) {
        inputElement = document.querySelector('#' +grid.value.ej2Instances.element.id + input.name);
      } else if (document.querySelector('#' + input.name)) {
          inputElement = document.querySelector('#' + input.name);
      }
      var inputPosition = inputElement.getBoundingClientRect();
      var leftPosition =  (inputPosition.left - tooltipWidth - 16).toString() + 'px';
      var topPosition = (inputPosition.top).toString() + 'px';
      element.style.left = leftPosition; 
      element.style.top =  topPosition;
      element.style.position = 'fixed';
    } 
  }
}
provide('grid', [Page, Edit, Toolbar]);
</script>
<style>
@import "../node_modules/@syncfusion/ej2-base/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-calendars/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-dropdowns/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-inputs/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-navigations/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-popups/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-vue-grids/styles/tailwind.css";
.e-gridform .e-arrow-tip.e-tip-top {
  transform: rotate(95deg);
  left: 126px;
  top: 7px;
}
</style>
<template>
  <div id="app">
    <ejs-grid ref="grid" :dataSource='dataGrid' :actionComplete='actionComplete' 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>
</template>
<script>
import { GridComponent, ColumnsDirective, ColumnDirective, Page, Toolbar, Edit,getObject } from "@syncfusion/ej2-vue-grids";

import { data } from './datasource.js';

export default {
  name: "App",
  components: {
    "ejs-grid": GridComponent,
    "e-columns": ColumnsDirective,
    "e-column": ColumnDirective,
  },
  data() {
    return {
      dataGrid: data,
      editSettings: { allowEditing: true, allowAdding: true, allowDeleting: true, mode: "Dialog" },
      toolbar: ["Add", "Edit", "Delete", "Update", "Cancel"],
      orderIDRules: { required: true, number: true },
      freightRules: { required: true, min: 1, max: 1000 },
      customerIDRules: { required: true },
      countryRules: { required: true },
      editparams: { params: { popupHeight: '200px' } },
      pageSettings: { pageCount: 5 }
    };
  },

  methods: {
    actionComplete(args) {
      if (args.requestType == "beginEdit" || args.requestType == "add") { 
         let editModule = this.$refs.grid.ej2Instances.editModule;
          let valueError = getObject('valErrorPlacement', editModule).bind(editModule);
            this.$refs.grid.ej2Instances.editModule.formObj.customPlacement = (input, error) => { 
              valueError(input, error);
              var element = document.getElementById(input.name + '_Error');
              var tooltipWidth = element.offsetWidth;
              var  inputElement = null;
              if (document.querySelector('#' + this.$refs.grid.ej2Instances.element.id + input.name)) {
                inputElement = document.querySelector('#' +this.$refs.grid.ej2Instances.element.id + input.name);
              } else if (document.querySelector('#' + input.name)) {
                inputElement = document.querySelector('#' + input.name);
              }
              var inputPosition = inputElement.getBoundingClientRect();
              var leftPosition =  (inputPosition.left - tooltipWidth - 16).toString() + 'px';
              var topPosition = (inputPosition.top).toString() + 'px';
              element.style.left = leftPosition; 
              element.style.top =  topPosition;
              element.style.position = 'fixed';
            } 
         
    
      }
    }
  },

  provide() {
    return {
      grid: [Page, Edit, Toolbar],
    };
  }
};
</script>

<style>
@import "../node_modules/@syncfusion/ej2-base/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-calendars/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-dropdowns/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-inputs/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-navigations/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-popups/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-vue-grids/styles/tailwind.css";
.e-gridform .e-arrow-tip.e-tip-top {
  transform: rotate(95deg);
  left: 126px;
  top: 7px;
}
</style>

Show custom error message while performing CRUD actions

While performing CRUD actions in the Syncfusion Vue Grid, errors may occur due to various reasons such as validation failures, network issues, or server-side exceptions. Handling these errors effectively is essential for providing meaningful error messages when an operation fails.

To achieve this, you can use the actionFailure event. This event is triggered when an action (like update, delete, or insert) fails, allowing you to retrieve the error message from the server response and display it in the UI.

The following sample demonstrates how to retrieve and display error messages in the Syncfusion Vue Grid:

<template>
    <div id="app">
        <p v-if="statusMessage" style="text-align: center; color: red">{{ statusMessage }}</p>
        <ejs-grid :dataSource='data' :toolbar="toolbar" :editSettings="editSettings" :actionFailure="actionFailure" allowPaging="true">
            <e-columns>
              <e-column field='OrderID' headerText='Order ID' width='120' textAlign='Right' isPrimaryKey="true"></e-column>
              <e-column field='CustomerID' headerText='Customer ID' width='160'></e-column>
              <e-column field='ShipCity' headerText='Ship City' width='150'></e-column>
              <e-column field='ShipCountry' headerText='Ship Country' width='150'></e-column>
            </e-columns>
        </ejs-grid>
    </div>
</template>
<script setup>
  import { provide,ref } from "vue";
  import { GridComponent as EjsGrid, ColumnDirective as EColumn, ColumnsDirective as EColumns, Page, Edit, Toolbar } from "@syncfusion/ej2-vue-grids";
  import { DataManager, UrlAdaptor } from "@syncfusion/ej2-data";
  const statusMessage = ref("");
  const data = new DataManager({
    url: 'https://localhost:****/api/Grid',
    insertUrl: 'https://localhost:****/api/Grid/Insert',
    updateUrl: 'https://localhost:****/api/Grid/Update',
    removeUrl: 'https://localhost:****/api/Grid/Remove',
    adaptor: new UrlAdaptor(),
  });// Replace your hosted link.
  const editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true };
  const toolbar = ['Add', 'Edit', 'Update', 'Delete', 'Cancel'];

  const actionFailure = function (args) {
    args.error?.[0]?.error?.json().then((data) => {
      statusMessage.value = data.message; // Set error message.
      }).catch(() => {
      statusMessage.value = "Error occurred, but message could not be retrieved.";
    });
  }
  provide('grid', [ Edit, Page, Toolbar]);
</script>
<style>
  @import "../node_modules/@syncfusion/ej2-base/styles/tailwind.css";
  @import "../node_modules/@syncfusion/ej2-buttons/styles/tailwind.css";
  @import "../node_modules/@syncfusion/ej2-calendars/styles/tailwind.css";
  @import "../node_modules/@syncfusion/ej2-dropdowns/styles/tailwind.css";
  @import "../node_modules/@syncfusion/ej2-inputs/styles/tailwind.css";
  @import "../node_modules/@syncfusion/ej2-navigations/styles/tailwind.css";
  @import "../node_modules/@syncfusion/ej2-popups/styles/tailwind.css";
  @import "../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind.css";
  @import "../node_modules/@syncfusion/ej2-vue-grids/styles/tailwind.css";
</style>
<template>
  <div id="app">
    <p v-if="statusMessage" style="text-align: center; color: red">{{ statusMessage }}</p>
    <ejs-grid :dataSource='data' :toolbar="toolbar" :editSettings="editSettings" :actionFailure="actionFailure" allowPaging="true">
      <e-columns>
        <e-column field='OrderID' headerText='Order ID' width='120' textAlign='Right' isPrimaryKey="true"></e-column>
        <e-column field='CustomerID' headerText='Customer ID' width='160'></e-column>
        <e-column field='ShipCity' headerText='Ship City' width='150'></e-column>
        <e-column field='ShipCountry' headerText='Ship Country' width='150'></e-column>
      </e-columns>
    </ejs-grid>
  </div>
</template>
<script>
import { GridComponent, ColumnsDirective, ColumnDirective,Edit, Page, Toolbar } from "@syncfusion/ej2-vue-grids";
import { DataManager, UrlAdaptor } from "@syncfusion/ej2-data";

export default {
  name: "App",
  components: {
    "ejs-grid": GridComponent,
    "e-columns": ColumnsDirective,
    "e-column": ColumnDirective,
  },
  data() {
    return {
      data:  new DataManager({
        url: 'https://localhost:****/api/Grid',
        insertUrl: 'https://localhost:****/api/Grid/Insert',
        updateUrl: 'https://localhost:****/api/Grid/Update',
        removeUrl: 'https://localhost:****/api/Grid/Remove',
        adaptor: new UrlAdaptor(),
    }), // Replace your hosted link.
    statusMessage:"",
    editSettings : { allowEditing: true, allowAdding: true, allowDeleting: true },
    toolbar : ['Add', 'Edit', 'Update', 'Delete', 'Cancel']
    };
  },
  methods: {
    actionFailure: function(args) {
      args.error?.[0]?.error?.json().then((data) => {
        this.statusMessage = data.message; // Set error message.
      }).catch(() => {
        this.statusMessage = "Error occurred, but message could not be retrieved.";
      });
    }
  },
  provide: {
    grid: [Edit, Page, Toolbar]
  }
}
</script>
<style>
  @import "../node_modules/@syncfusion/ej2-base/styles/tailwind.css";
  @import "../node_modules/@syncfusion/ej2-buttons/styles/tailwind.css";
  @import "../node_modules/@syncfusion/ej2-calendars/styles/tailwind.css";
  @import "../node_modules/@syncfusion/ej2-dropdowns/styles/tailwind.css";
  @import "../node_modules/@syncfusion/ej2-inputs/styles/tailwind.css";
  @import "../node_modules/@syncfusion/ej2-navigations/styles/tailwind.css";
  @import "../node_modules/@syncfusion/ej2-popups/styles/tailwind.css";
  @import "../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind.css";
  @import "../node_modules/@syncfusion/ej2-vue-grids/styles/tailwind.css";
</style>
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 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 DataOperations 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 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/Grid/Insert")]
    public IActionResult Insert([FromBody] CRUDModel<OrdersDetails> newRecord)
    {
      if (newRecord.value == null)
      {
        return BadRequest(new { message = "Invalid data received." });
      }
      var existingOrder = OrdersDetails.order.FirstOrDefault(or => or.OrderID == newRecord.value.OrderID);
      if (existingOrder == null)
      {
        OrdersDetails.order.Insert(0, newRecord.value);
        return Ok(new { success = true, message = "Order added successfully.", data = newRecord.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/Grid/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/Grid/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);
      if (data != null)
      {
        OrdersDetails.GetAllRecords().Remove(data);
        return Ok(new { success = true, message = "Order deleted successfully." });
      }
      return NotFound(new { message = "Order not found." });
    }

    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 illustrates how to retrieve and display error messages when CRUD operations fail:

custom error message