Welcome to the mention integration with rich text editor demo. Type @ character and tag user from the suggestion list.
";
+ @ViewChild('mention') mentionObj!: Mention;
+ @ViewChild('mentionRTE') rteObj!: RichTextEditorComponent;
+
+ public iframe = { enable: true };
+ public target: any;
+ public toolbarSettings: ToolbarSettingsModel = {
+ items: ['Bold', 'Italic', 'Underline', '|', 'Formats', 'Alignments', 'OrderedList',
+ 'UnorderedList', '|', 'CreateLink', 'Image', '|', 'SourceCode', '|', 'Undo', 'Redo'
+ ]
+ };
+ public data: { [key: string]: MentionModule }[] = [
+ { Name: "Selma Rose", Status: "active", Eimg: "2", EmailId: "selma@gmail.com" },
+ { Name: "Maria", Status: "active", Eimg: "1", EmailId: "maria@gmail.com" },
+ { Name: "Russo Kay", Status: "busy", Eimg: "8", EmailId: "russo@gmail.com" },
+ { Name: "Camden Kate", Status: "active", Eimg: "9", EmailId: "camden@gmail.com" },
+ { Name: "Robert", Status: "busy", Eimg: "dp", EmailId: "robert@gmail.com" },
+ { Name: "Garth", Status: "active", Eimg: "7", EmailId: "garth@gmail.com" },
+ { Name: "Andrew James", Status: "away", Eimg: "pic04", EmailId: "noah@gmail.com" },
+ { Name: "Olivia", Status: "busy", Eimg: "5", EmailId: "olivia@gmail.com" },
+ { Name: "Sophia", Status: "away", Eimg: "6", EmailId: "sophia@gmail.com" },
+ { Name: "Margaret", Status: "active", Eimg: "3", EmailId: "margaret@gmail.com" },
+ { Name: "Ursula Ann", Status: "active", Eimg: "dp", EmailId: "ursula@gmail.com" },
+ { Name: "Laura Grace", Status: "away", Eimg: "4", EmailId: "laura@gmail.com" },
+ { Name: "Albert", Status: "active", Eimg: "pic03", EmailId: "albert@gmail.com" },
+ { Name: "William", Status: "away", Eimg: "10", EmailId: "william@gmail.com" }
+ ];
+ public fieldsData: { [key: string]: string } = { text: 'Name' };
+
+ onActionBegin(args: ActionBeginEventArgs) {
+ if (args.requestType === 'EnterAction' && this.mentionObj.element.classList.contains('e-popup-open')) {
+ args.cancel = true;
+ }
+ }
+ created() {
+ // here assigned the RichTextEditor's inputElement as the Mention's target
+ this.target = this.rteObj.inputElement;
+ }
+}
\ No newline at end of file
diff --git a/ej2-angular/code-snippet/rich-text-editor/mention-iframe/src/app.style.css b/ej2-angular/code-snippet/rich-text-editor/mention-iframe/src/app.style.css
new file mode 100644
index 0000000000..f2f2a026a1
--- /dev/null
+++ b/ej2-angular/code-snippet/rich-text-editor/mention-iframe/src/app.style.css
@@ -0,0 +1,11 @@
+.below-30 {
+ background-color: orangered;
+ }
+
+ .below-80 {
+ background-color: yellow;
+ }
+
+ .above-80 {
+ background-color: greenyellow
+ }
\ No newline at end of file
diff --git a/ej2-angular/code-snippet/rich-text-editor/mention-iframe/src/main.ts b/ej2-angular/code-snippet/rich-text-editor/mention-iframe/src/main.ts
new file mode 100644
index 0000000000..3607237bd6
--- /dev/null
+++ b/ej2-angular/code-snippet/rich-text-editor/mention-iframe/src/main.ts
@@ -0,0 +1,4 @@
+import { bootstrapApplication } from '@angular/platform-browser';
+import { AppComponent } from './app.component';
+import 'zone.js';
+bootstrapApplication(AppComponent).catch((err) => console.error(err));
\ No newline at end of file
diff --git a/ej2-angular/code-snippet/rich-text-editor/mention-iframe/src/styles.css b/ej2-angular/code-snippet/rich-text-editor/mention-iframe/src/styles.css
new file mode 100644
index 0000000000..a6eb7ef2b5
--- /dev/null
+++ b/ej2-angular/code-snippet/rich-text-editor/mention-iframe/src/styles.css
@@ -0,0 +1,15 @@
+@import 'node_modules/@syncfusion/ej2-base/styles/material.css';
+@import 'node_modules/@syncfusion/ej2-icons/styles/material.css';
+@import 'node_modules/@syncfusion/ej2-buttons/styles/material.css';
+@import 'node_modules/@syncfusion/ej2-splitbuttons/styles/material.css';
+@import 'node_modules/@syncfusion/ej2-inputs/styles/material.css';
+@import 'node_modules/@syncfusion/ej2-lists/styles/material.css';
+@import 'node_modules/@syncfusion/ej2-navigations/styles/material.css';
+@import 'node_modules/@syncfusion/ej2-popups/styles/material.css';
+@import 'node_modules/@syncfusion/ej2-richtexteditor/styles/material.css';
+@import 'node_modules/@syncfusion/ej2-angular-buttons/styles/material.css';
+@import 'node_modules/@syncfusion/ej2-angular-base/styles/material.css';
+@import 'node_modules/@syncfusion/ej2-angular-dropdowns/styles/material.css';
+@import 'node_modules/@syncfusion/ej2-angular-inputs/styles/material.css';
+@import 'node_modules/@syncfusion/ej2-angular-popups/styles/material.css';
+@import 'node_modules/@syncfusion/ej2-angular-richtexteditor/styles/material.css';
diff --git a/ej2-angular/code-snippet/rich-text-editor/mention-iframe/tsconfig.json b/ej2-angular/code-snippet/rich-text-editor/mention-iframe/tsconfig.json
new file mode 100644
index 0000000000..9fa16d6333
--- /dev/null
+++ b/ej2-angular/code-snippet/rich-text-editor/mention-iframe/tsconfig.json
@@ -0,0 +1,32 @@
+{
+ "compileOnSave": false,
+ "compilerOptions": {
+ "baseUrl": "./",
+ "outDir": "./dist/out-tsc",
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true,
+ "sourceMap": true,
+ "declaration": false,
+ "downlevelIteration": true,
+ "experimentalDecorators": true,
+ "moduleResolution": "node",
+ "importHelpers": true,
+ "target": "ES2022",
+ "module": "ES2022",
+ "useDefineForClassFields": false,
+ "lib": [
+ "ES2022",
+ "dom"
+ ]
+ },
+ "angularCompilerOptions": {
+ "enableI18nLegacyMessageIdFormat": false,
+ "strictInjectionParameters": true,
+ "strictInputAccessModifiers": true,
+ "strictTemplates": true
+ }
+}
\ No newline at end of file
diff --git a/ej2-angular/gantt/excel-export/custom-data-source.md b/ej2-angular/gantt/excel-export/custom-data-source.md
index 1f56e97ed3..c94e3b91fc 100644
--- a/ej2-angular/gantt/excel-export/custom-data-source.md
+++ b/ej2-angular/gantt/excel-export/custom-data-source.md
@@ -10,7 +10,7 @@ domainurl: ##DomainURL##
# Custom data source in Angular Gantt component
-The excel export provides an option to define datasource dynamically before exporting. To export data dynamically, define the `dataSource` in `exportProperties`.
+The excel export provides an option to define datasource dynamically before exporting. To export data dynamically, define the [`dataSource`](https://ej2.syncfusion.com/angular/documentation/api/grid/excelExportProperties/#datasource) in [`ExcelExportProperties`](https://ej2.syncfusion.com/angular/documentation/api/grid/excelExportProperties/).
{% tabs %}
{% highlight ts tabtitle="app.component.ts" %}
@@ -22,4 +22,4 @@ The excel export provides an option to define datasource dynamically before expo
{% endhighlight %}
{% endtabs %}
-{% previewsample "page.domainurl/samples/gantt/excel-export/customData-cs1" %}
\ No newline at end of file
+{% previewsample "page.domainurl/samples/gantt/excel-export/customData-cs1" %}
diff --git a/ej2-angular/gantt/excel-export/multiple-gantt-exporting.md b/ej2-angular/gantt/excel-export/multiple-gantt-exporting.md
index a4700db7e8..fd5964090b 100644
--- a/ej2-angular/gantt/excel-export/multiple-gantt-exporting.md
+++ b/ej2-angular/gantt/excel-export/multiple-gantt-exporting.md
@@ -15,7 +15,7 @@ In Gantt, the Excel export provides support to export multiple Gantt data in new
## Same sheet
-The Excel export provides support to export multiple Gantt data in the same sheet. To export in same sheet, define `multipleExport.type` as `AppendToSheet` in `ExcelExportProperties`. You can also provide blank rows between exported multiple Gantt data. These blank rows count can be defined using `multipleExport.blankRows`.
+The Excel export provides support to export multiple Gantt data in the same sheet. To export in same sheet, define [`multipleExport.type`](https://ej2.syncfusion.com/angular/documentation/api/grid/excelExportProperties/#multipleexport) as `AppendToSheet` in [`ExcelExportProperties`](https://ej2.syncfusion.com/angular/documentation/api/grid/excelExportProperties/). You can also provide blank rows between exported multiple Gantt data. These blank rows count can be defined using `multipleExport.blankRows`.
{% tabs %}
{% highlight ts tabtitle="app.component.ts" %}
@@ -33,7 +33,7 @@ The Excel export provides support to export multiple Gantt data in the same shee
## New sheet
-The Excel exporting provides support to export multiple Gantt in new sheet. To export in new sheet, define `multipleExport.type` as `NewSheet` in `ExcelExportProperties`.
+The Excel exporting provides support to export multiple Gantt in new sheet. To export in new sheet, define [`multipleExport.type`](https://ej2.syncfusion.com/angular/documentation/api/grid/excelExportProperties/#multipleexport) as `NewSheet` in [`ExcelExportProperties`](https://ej2.syncfusion.com/angular/documentation/api/grid/excelExportProperties/).
{% tabs %}
{% highlight ts tabtitle="app.component.ts" %}
@@ -53,7 +53,7 @@ Gantt Excel export allows the users to customize the exported document based on
### Export hidden columns
-In Gantt, the Excel export provides an option to export hidden columns by defining `includeHiddenColumn` as `true`.
+In Gantt, the Excel export provides an option to export hidden columns by defining [`includeHiddenColumn`](https://ej2.syncfusion.com/angular/documentation/api/treegrid/treeGridExcelExportProperties/#includehiddencolumn) as `true`.
{% tabs %}
{% highlight ts tabtitle="app.component.ts" %}
@@ -109,7 +109,7 @@ In the following sample, the background color has been customized for `TaskID` c
The Excel export also provides an option to include custom theme for exported Excel document.
-To apply theme in exported Excel, define the `theme` in `ExcelExportProperties`.
+To apply theme in exported Excel, define the [`theme`](https://ej2.syncfusion.com/angular/documentation/api/grid/excelExportProperties/#theme) in [`ExcelExportProperties`](https://ej2.syncfusion.com/angular/documentation/api/grid/excelExportProperties/).
{% tabs %}
{% highlight ts tabtitle="app.component.ts" %}
@@ -143,7 +143,7 @@ The Excel export also allows users to include header and footer contents to the
### File name for exported document
-You can set the required file name for the exported document by defining the `fileName` property in `ExcelExportProperties`.
+You can set the required file name for the exported document by defining the [`fileName`](https://ej2.syncfusion.com/angular/documentation/api/grid/excelExportProperties/#filename) property in `ExcelExportProperties`.
{% tabs %}
{% highlight ts tabtitle="app.component.ts" %}
@@ -155,4 +155,4 @@ You can set the required file name for the exported document by defining the `fi
{% endhighlight %}
{% endtabs %}
-{% previewsample "page.domainurl/samples/gantt/excel-export/fileName-cs1" %}
\ No newline at end of file
+{% previewsample "page.domainurl/samples/gantt/excel-export/fileName-cs1" %}
diff --git a/ej2-angular/gantt/module.md b/ej2-angular/gantt/module.md
index a4867e9217..7f06915fa7 100644
--- a/ej2-angular/gantt/module.md
+++ b/ej2-angular/gantt/module.md
@@ -10,24 +10,25 @@ domainurl: ##DomainURL##
# Module in Angular Gantt component
-The modules that are available in Gantt are as follows.
+The following value providers must be injected to extend the Gantt chart's functionality.
| Module | Description |
|------|-------------|
-| [`Sort`](https://ej2.syncfusion.com/angular/documentation/api/gantt/sort)| Inject this module to use sorting feature.|
-| [`Filter`](https://ej2.syncfusion.com/angular/documentation/api/gantt/filter)| Inject this module to use filtering feature.|
-| [`Reorder`](https://ej2.syncfusion.com/angular/documentation/api/grid/reorder) | Inject this module to use reorder feature.|
-| [`ExcelExport`](https://ej2.syncfusion.com/documentation/api/gantt/#excelexportmodule) | Inject this module to use excel export feature.|
-| [`PdfExport`](https://ej2.syncfusion.com/documentation/api/gantt/#pdfexportmodule) | Inject this module to use PDF export feature.|
-| [`RowDD`](https://ej2.syncfusion.com/angular/documentation/api/gantt/rowDD)| Inject this module to use row drag and drop feature.|
-| `Resize`| Inject this module to use resize feature.|
-| [`Toolbar`](https://ej2.syncfusion.com/angular/documentation/api/gantt/#toolbar)| Inject this module to use toolbar feature.|
-| [`Edit`](https://ej2.syncfusion.com/angular/documentation/api/gantt/edit)| Inject this module is use editing feature.|
-| [`Selection`](https://ej2.syncfusion.com/angular/documentation/api/gantt/selection)| Inject this module to use selection feature.|
-| [`DayMarkers`](https://ej2.syncfusion.com/angular/documentation/api/gantt/dayMarkers)| Inject this module to use event markers.|
-| [`ContextMenu`](https://ej2.syncfusion.com/documentation/api/gantt/contextMenu/)| Inject this module to use context menu feature.|
-| [`ColumnMenu`](https://ej2.syncfusion.com/documentation/api/gantt/columnMenu/#getcolumnmenu)| Inject this module to use column menu feature.|
-| [`VirtualScroll`](https://ej2.syncfusion.com/angular/documentation/api/gantt/#virtualscrollmodule)| Inject this module to use virtual scroll feature.|
-| [`CriticalPath`](https://ej2.syncfusion.com/angular/documentation/api/gantt/#criticalpathmodule)| Inject this module to use critical path feature.|
+| [`SortService`](https://ej2.syncfusion.com/angular/documentation/api/gantt/sort)| Inject this module to use sorting feature.|
+| [`FilterService`](https://ej2.syncfusion.com/angular/documentation/api/gantt/filter)| Inject this module to use filtering feature.|
+| [`ReorderService`](https://ej2.syncfusion.com/angular/documentation/api/grid/reorder) | Inject this module to use reorder feature.|
+| [`ExcelExportService`](https://ej2.syncfusion.com/documentation/api/gantt/#excelexportmodule) | Inject this module to use excel export feature.|
+| [`PdfExportService`](https://ej2.syncfusion.com/documentation/api/gantt/#pdfexportmodule) | Inject this module to use PDF export feature.|
+| [`RowDDService`](https://ej2.syncfusion.com/angular/documentation/api/gantt/rowDD)| Inject this module to use row drag and drop feature.|
+| `ResizeService`| Inject this module to use resize feature.|
+| [`ToolbarService`](https://ej2.syncfusion.com/angular/documentation/api/gantt/#toolbar)| Inject this module to use toolbar feature.|
+| [`EditService`](https://ej2.syncfusion.com/angular/documentation/api/gantt/edit)| Inject this module is use editing feature.|
+| [`SelectionService`](https://ej2.syncfusion.com/angular/documentation/api/gantt/selection)| Inject this module to use selection feature.|
+| [`DayMarkersService`](https://ej2.syncfusion.com/angular/documentation/api/gantt/dayMarkers)| Inject this module to use event markers.|
+| [`ContextMenuService`](https://ej2.syncfusion.com/documentation/api/gantt/contextMenu/)| Inject this module to use context menu feature.|
+| [`ColumnMenuService`](https://ej2.syncfusion.com/angular/documentation/api/gantt/#columnmenumodule)| Inject this module to use column menu feature.|
+| [`VirtualScrollService`](https://ej2.syncfusion.com/angular/documentation/api/gantt/#virtualscrollmodule)| Inject this module to use virtual scroll feature.|
+| [`CriticalPathService`](https://ej2.syncfusion.com/angular/documentation/api/gantt/#criticalpathmodule)| Inject this module to use critical path feature.|
+| [`UndoRedoService`](https://ej2.syncfusion.com/angular/documentation/api/gantt/#undoredomodule)| Inject this module to use undo redo feature.|
-These modules should be injected into the Gantt using the **Gantt.Inject** method.
+These modules should be injected into the providers section of the root NgModule or a component class.
diff --git a/ej2-angular/gantt/pdf-export/customize-pdf-export.md b/ej2-angular/gantt/pdf-export/customize-pdf-export.md
index 479df24fe9..c0d53f0c0f 100644
--- a/ej2-angular/gantt/pdf-export/customize-pdf-export.md
+++ b/ej2-angular/gantt/pdf-export/customize-pdf-export.md
@@ -47,7 +47,7 @@ The page orientation of the exported PDF document can be customized using the [p
## How to change page size
Page size can be customized for the exported document using the [pageSize](https://helpej2.syncfusion.com/angular/documentation/api/gantt/pdfExportProperties/#pagesize) property in [pdfExportProperties](https://helpej2.syncfusion.com/angular/documentation/api/gantt/pdfExportProperties/).
- The supported page sizes are:
+The supported page sizes are:
* Letter
* Note
@@ -106,6 +106,22 @@ PDF export provides an option to export the current view data into PDF. To expor
{% previewsample "page.domainurl/samples/gantt/pdf-export-cs4" %}
+## Enable footer
+
+By default, we render the default footer for a PDF file, this can be enabled or disabled by using the [`enableFooter`](https://ej2.syncfusion.com/angular/documentation/api/gantt/pdfExportProperties/#enablefooter) property.
+
+{% tabs %}
+{% highlight ts tabtitle="app.component.ts" %}
+{% include code-snippet/gantt/pdf-export-cs5/src/app.component.ts %}
+{% endhighlight %}
+
+{% highlight ts tabtitle="main.ts" %}
+{% include code-snippet/gantt/pdf-export-cs5/src/main.ts %}
+{% endhighlight %}
+{% endtabs %}
+
+{% previewsample "page.domainurl/samples/gantt/pdf-export-cs5" %}
+
## Export hidden columns
PDF export provides an option to export hidden columns of Gantt by defining the [includeHiddenColumn](https://helpej2.syncfusion.com/angular/documentation/api/gantt/pdfExportProperties/#includehiddencolumn) to `true`.
@@ -178,9 +194,9 @@ In the following sample, the background color is set for `Progress` column in th
## Timeline cell formatting
-Timeline cells in the exported PDF document can be customized or formatted using the [`pdfQueryTimelineCellInfo`](https://ej2.syncfusion.com/angular/documentation/api/treegrid#pdfquerytimelinecellinfo) event.
+Timeline cells in the exported PDF document can be customized or formatted using the [`pdfQueryTimelineCellInfo`](https://ej2.syncfusion.com/angular/documentation/api/gantt/#pdfquerytimelinecellinfo) event.
-In the following sample, the header background color is set for timeline cells in the exported document by using the `args.headerBackgroundColor` property.
+In the following sample, the header background color is set for timeline cells in the exported document by using the `args.timelineCell.backgroundColor` property.
{% tabs %}
{% highlight ts tabtitle="app.component.ts" %}
@@ -196,7 +212,7 @@ In the following sample, the header background color is set for timeline cells i
## Taskbar formatting
-Taskbars in the exported PDF document can be customized or formatted using the [`pdfQueryTaskbarInfo`](https://ej2.syncfusion.com/angular/documentation/api/treegrid#pdfquerytaskbarinfo) event.
+Taskbars in the exported PDF document can be customized or formatted using the [`pdfQueryTaskbarInfo`](https://ej2.syncfusion.com/angular/documentation/api/gantt/#pdfquerytaskbarinfo) event.
In the following sample, the taskbar background color is customized in the chart side of the exported document by using the `args.taskbar` property.
@@ -212,12 +228,10 @@ In the following sample, the taskbar background color is customized in the chart
{% previewsample "page.domainurl/samples/gantt/pdf-export-cs11" %}
-
## Customize Gantt Chart Appearance in PDF Export
PDF export allows to customize the Gantt chart's appearance in the exported PDF documents. To customize the appearance of Gantt charts in exported PDF documents, define [ganttStyle](https://ej2.syncfusion.com/angular/documentation/api/gantt/pdfExportProperties/#ganttstyle) within [pdfExportProperties](https://ej2.syncfusion.com/angular/documentation/api/gantt/pdfExportProperties/). By using `ganttStyle`, can customize `columnHeader`, `fontFamily`, `cell`, `taskbar`, `label`, `timeline`, `chartGridLineColor`, `connectorLineColor`, `criticalConnectorLineColor`, `footer`, `font`, `eventMarker` and `holiday` regardless of the theme.
-
{% tabs %}
{% highlight ts tabtitle="app.component.ts" %}
{% include code-snippet/gantt/pdf-export-cs13/src/app.component.ts %}
diff --git a/ej2-angular/gantt/pdf-export/header-and-footer.md b/ej2-angular/gantt/pdf-export/header-and-footer.md
index 6a214ff60e..5f71213a0c 100644
--- a/ej2-angular/gantt/pdf-export/header-and-footer.md
+++ b/ej2-angular/gantt/pdf-export/header-and-footer.md
@@ -38,6 +38,7 @@ let exportProperties: PdfExportProperties = {
]
}
+}
```
@@ -76,7 +77,7 @@ let exportProperties: PdfExportProperties = {
## Add page number in header and footer
-This feature allows to customize the page number that appears in the header or footer sections of the PDF document. Page numbers can be added in [header](https://helpej2.syncfusion.com/angular/documentation/api/gantt/pdfHeader/) or [footer](https://helpej2.syncfusion.com/react/documentation/api/gantt/pdfFooter/) of the exported PDF document by using [pdfExportProperties](https://helpej2.syncfusion.com/react/documentation/api/gantt/pdfExportProperties/).
+This feature allows to customize the page number that appears in the header or footer sections of the PDF document. Page numbers can be added in [`header`](https://ej2.syncfusion.com/angular/documentation/api/gantt/pdfExportProperties/#header) or [`footer`](https://ej2.syncfusion.com/angular/documentation/api/gantt/pdfExportProperties/#footer) of the exported PDF document by using [pdfExportProperties](https://helpej2.syncfusion.com/react/documentation/api/gantt/pdfExportProperties/).
* `type` indicates that the content is a page number.
* `pageNumberType` specifies the type of numbering to be used.
@@ -113,7 +114,7 @@ Supported page number types:
## Insert an image in header and footer
-This feature allows to customize the image that appears in the header or footer sections of the PDF document. Image (Base64 string) can be added in the exported document in [header](https://helpej2.syncfusion.com/react/documentation/api/gantt/pdfHeader/) or [footer](https://helpej2.syncfusion.com/react/documentation/api/gantt/pdfFooter/) of the exported PDF document by using [pdfExportProperties](https://helpej2.syncfusion.com/react/documentation/api/gantt/pdfExportProperties/).
+This feature allows to customize the image that appears in the header or footer sections of the PDF document. Image (Base64 string) can be added in the exported document in [`header`](https://ej2.syncfusion.com/angular/documentation/api/gantt/pdfExportProperties/#header) or [`footer`](https://ej2.syncfusion.com/angular/documentation/api/gantt/pdfExportProperties/#footer) of the exported PDF document by using [pdfExportProperties](https://ej2.syncfusion.com/angular/documentation/api/gantt/pdfExportProperties/).
* `type` indicates that the content is an image.
* `src` specifies the source of the image, which should be Base64 string.
diff --git a/ej2-angular/gantt/pdf-export/pdf-export.md b/ej2-angular/gantt/pdf-export/pdf-export.md
index da3f62ecf0..88b50cc3f9 100644
--- a/ej2-angular/gantt/pdf-export/pdf-export.md
+++ b/ej2-angular/gantt/pdf-export/pdf-export.md
@@ -37,11 +37,11 @@ These indicators, represented by images,can be effortlessly defined using the [
{% tabs %}
{% highlight ts tabtitle="app.component.ts" %}
-{% include code-snippet/gantt/pdf-export-cs14/src/app.component.ts %}
+{% include code-snippet/gantt/pdf-export-cs15/src/app.component.ts %}
{% endhighlight %}
{% highlight ts tabtitle="main.ts" %}
-{% include code-snippet/gantt/pdf-export-cs14/src/main.ts %}
+{% include code-snippet/gantt/pdf-export-cs15/src/main.ts %}
{% endhighlight %}
{% endtabs %}
diff --git a/ej2-angular/grid/columns/foreign-key-column.md b/ej2-angular/grid/columns/foreign-key-column.md
index 9902539505..02e65ae1db 100644
--- a/ej2-angular/grid/columns/foreign-key-column.md
+++ b/ej2-angular/grid/columns/foreign-key-column.md
@@ -642,6 +642,6 @@ app.Run();
```
-
+
diff --git a/ej2-angular/grid/columns/frozen-column.md b/ej2-angular/grid/columns/frozen-column.md
index 24a9b96205..7885dade14 100644
--- a/ej2-angular/grid/columns/frozen-column.md
+++ b/ej2-angular/grid/columns/frozen-column.md
@@ -30,6 +30,7 @@ In the following example, the [frozenColumns](https://ej2.syncfusion.com/angular
> * Frozen Grid support column virtualization feature, which helps to improve the Grid performance while loading a large dataset.
> * The frozen feature is supported only for the columns that are visible in the current view.
> * You can use both `frozenColumns` property and [frozenRows](https://ej2.syncfusion.com/angular/documentation/api/grid/#frozenrows) property in the same application.
+> * When both frozen columns and column virtualization are enabled, horizontal scrolling using touchpad gestures (e.g., two-finger swipe) is not supported. Users must use the horizontal scrollbar to scroll the Grid content.
## Freeze particular columns
diff --git a/ej2-angular/grid/connecting-to-database/dapper.md b/ej2-angular/grid/connecting-to-database/dapper.md
index 9b88d772f6..0d94a3061e 100644
--- a/ej2-angular/grid/connecting-to-database/dapper.md
+++ b/ej2-angular/grid/connecting-to-database/dapper.md
@@ -939,7 +939,9 @@ public class CRUDModel where T : class
When you run the application, the resultant Grid will look like this
-
+
+
+> Please find the sample in this [GitHub location](https://github.com/SyncfusionExamples/connecting-databases-to-angular-grid/tree/master/Binding%20Dapper%20using%20UrlAdaptor/Grid_Dapper).
## Binding data from Microsoft SQL Server using Dapper with CustomAdaptor
@@ -1786,7 +1788,7 @@ public class CRUDModel where T : class
{% endhighlight %}
{% endtabs %}
-## Batch Operation:
+**Batch Operation:**
To perform the batch operation, override the **batchRequest** method of the `CustomAdaptor` and add the following code in the `CustomAdaptor`. The below code snippet demonstrated how to handle the batch update request within the **batchRequest** method of `CustomAdaptor`. Modify the logic within this method according to the requirements of your application.
@@ -1904,4 +1906,6 @@ public class CRUDModel where T : class
{% endhighlight %}
{% endtabs %}
-
\ No newline at end of file
+
+
+> Please find the sample in this [GitHub location](https://github.com/SyncfusionExamples/connecting-databases-to-angular-grid/tree/master/Binding%20Dapper%20using%20CustomAdaptor/Grid_Dapper_CustomAdaptor).
\ No newline at end of file
diff --git a/ej2-angular/grid/connecting-to-database/entityframework.md b/ej2-angular/grid/connecting-to-database/entityframework.md
new file mode 100644
index 0000000000..f6e3f69eea
--- /dev/null
+++ b/ej2-angular/grid/connecting-to-database/entityframework.md
@@ -0,0 +1,2127 @@
+---
+layout: post
+title: Bind SQL Server Data in Syncfusion Angular Grid using Entity Framework
+description: Learn about consume data using Entity Framework from Microsoft SQL Server, bind it to Syncfusion Angular Grid, and performing CRUD operations.
+platform: ej2-angular
+control: grid
+keywords: adaptors, customadaptor, urladaptor, entityframework, remotedata
+documentation: ug
+domainurl: ##DomainURL##
+---
+
+# Connecting SQL Server data to Syncfusion Angular Grid using Entity Framework
+
+This section describes how to connect and retrieve data from a Microsoft SQL Server database using [Entity Framework](https://learn.microsoft.com/en-us/ef/core/) and bind it to the Syncfusion Angular Grid.
+
+Microsoft SQL Server database can be bound to the Grid using **Entity Framework** in different ways (i.e.) using [dataSource](https://ej2.syncfusion.com/angular/documentation/api/grid/#datasource) property, custom adaptor and remote data binding using various adaptors. In this documentation, two approaches will be examined to connect a Microsoft SQL Server database to a Grid using **Entity Framework**. Both the approaches have capability to handle data and CRUD operations with built-in methods as well as can be customized as per your own.
+
+**Entity Framework**
+
+Entity Framework is an open-source [ORM framework](https://en.wikipedia.org/wiki/Object-relational_mapping) for .NET applications supported by Microsoft. It enables developers to work with data using objects of domain specific classes without focusing on the underlying database tables and columns where this data is stored. With the Entity Framework, developers can work at a higher level of abstraction when they deal with data, and can create and maintain data-oriented applications with less code compared with traditional applications.
+
+**1. Using UrlAdaptor**
+
+The [UrlAdaptor](https://ej2.syncfusion.com/angular/documentation/grid/connecting-to-adaptors/url-adaptor?cs-save-lang=1&cs-lang=csharp) serves as the base adaptor for facilitating communication between remote data services and an UI component. It enables the remote binding of data to the Syncfusion Angular Grid by connecting to an existing pre-configured API service linked to the Microsoft SQL Server database. While the Grid supports various adaptors to fulfill this requirement, including [Web API](https://ej2.syncfusion.com/angular/documentation/grid/connecting-to-adaptors/web-api-adaptor), [ODataV4](https://ej2.syncfusion.com/angular/documentation/grid/connecting-to-adaptors/odatav4-adaptor), [UrlAdaptor](https://ej2.syncfusion.com/angular/documentation/grid/connecting-to-adaptors/url-adaptor?cs-save-lang=1&cs-lang=csharp), and [GraphQL](https://ej2.syncfusion.com/angular/documentation/grid/connecting-to-adaptors/graphql-adaptor), the `UrlAdaptor` is particularly useful for the scenarios where a custom API service with unique logic for handling data and CRUD operations is in place. This approach allows for custom handling of data and CRUD operations, and the resultant data returned in the `result` and `count` format for display in the Grid.
+
+**2. Using CustomAdaptor**
+
+The [CustomAdaptor](https://ej2.syncfusion.com/angular/documentation/grid/connecting-to-adaptors/custom-adaptor) serves as a mediator between the UI component and the database for data binding. While the data source from the database can be directly bound to the Syncfusion Angular Grid locally using the `dataSource` property, the `CustomAdaptor` approach is preferred as it allows for customization of both data operations and CRUD operations according to specific requirements. In this approach, for every action in the Grid, a corresponding request with action details is sent to the `CustomAdaptor`. The Grid provides predefined methods to perform data operations such as **searching**, **filtering**, **sorting**, **aggregation**, **paging** and **grouping**. Alternatively, your own custom methods can be employed to execute operations and return the data in the `result` and `count` format for displaying in the Grid. Additionally, for CRUD operations, predefined methods can be overridden to provide custom functionality. Further details on this can be found in the latter part of the documentation.
+
+## Binding data using Entity Framework from Microsoft SQL Server via an API service.
+
+This section describes step by step process how to use Entity Framework to retrieve data from a Microsoft SQL Server using an API service and bind it to the Syncfusion Angular Grid.
+
+### Creating an API service
+
+**1.** Open Visual Studio and create an Angular and ASP.NET Core project named **Grid_EntityFramework**. To create an Angular and ASP.NET Core application, follow the documentation [link](https://learn.microsoft.com/en-us/visualstudio/javascript/tutorial-asp-net-core-with-angular?view=vs-2022) for detailed steps.
+
+**2.** To use Entity Framework and access the Microsoft SQL Server database in our Angular application, need to install the [Microsoft.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.SqlServer/) and [Microsoft.EntityFrameworkCore](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore) NuGet packages. To add **Microsoft.EntityFrameworkCore** and **Microsoft.EntityFrameworkCore.SqlServer** in the app, open the NuGet package manager in Visual Studio (Tools → NuGet Package Manager → Manage NuGet Packages for Solution), search and install it.
+
+**3.** Create an API controller (aka, GridController.cs) file under **Controllers** folder that helps to establish data communication with the Syncfusion Angular Grid.
+
+**4** In the API controller (aka, GridController), a connection is established to Microsoft SQL Server within the **GetOrderData()** method using **OrderDbContext**. This class extends **DbContext** and is configured to connect to a Microsoft SQL Server database using the provided connection string. It includes a *DbSet<Orders>** property, enabling interaction with the **Orders** table in the database. The method retrieves all orders from the database asynchronously and returns them as a list of `Orders` objects as shown in the following code snippet.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+using Microsoft.AspNetCore.Mvc;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Data;
+using Syncfusion.EJ2.Base;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Internal;
+
+namespace Grid_EntityFramework.Server.Controllers
+{
+ [ApiController]
+ public class GridController : ControllerBase
+ {
+ string ConnectionString = @"";
+
+ ///
+ /// Processes the DataManager request to perform searching, filtering, sorting, and paging operations.
+ ///
+ /// Contains the details of the data operation requested.
+ /// Returns a JSON object along with the total record count.
+ [HttpPost]
+ [Route("api/[controller]")]
+ public object Post([FromBody] DataManagerRequest DataManagerRequest)
+ {
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+ }
+
+ ///
+ /// Retrieves the order data from the database.
+ ///
+ /// Returns a list of orders fetched from the database.
+ [HttpGet]
+ [Route("api/[controller]")]
+ public List GetOrderData()
+ {
+ using (OrderDbContext Context = new OrderDbContext(ConnectionString))
+ {
+ // Retrieve orders from the orders DbSet and convert to list asynchronously.
+ List orders = Context.Orders.ToList();
+ return orders;
+ }
+ }
+
+ // Create a class that inherits from DbContext(Entity Framework Core).
+ public class OrderDbContext : DbContext
+ {
+ //Declare a private variable to store the connection string.
+ private readonly string _ConnectionString;
+
+ //Define a constructor that accepts a connection string.
+ public OrderDbContext(string ConnectionString)
+ {
+ //Store the provided connection string.
+ _ConnectionString = ConnectionString;
+ }
+
+ //Override the onConfiguring method to tell EF Core to use SQL server.
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ // Use the connection string to configure the database connection.
+ optionsBuilder.UseSqlServer(_ConnectionString);
+ }
+
+ // Define a DbSet to represent the orders table in the database.
+ public DbSet Orders { get; set; }
+ }
+
+ public class Orders
+ {
+ [Key]
+ public int? OrderID { get; set; }
+ public string? CustomerID { get; set; }
+ public int? EmployeeID { get; set; }
+ public decimal Freight { get; set; }
+ public string? ShipCity { get; set; }
+ }
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**5.** Run the application and it will be hosted within the URL `https://localhost:xxxx`.
+
+**6.** Finally, the retrieved data from Microsoft SQL Server database using Entity Framework which is in the form of list can be found in an API controller available in the URL link `https://localhost:xxxx/api/Grid`, as shown in the browser page below.
+
+
+
+### Connecting Syncfusion Angular Grid to an API service
+
+To integrate the Syncfusion Angular Grid into your Angular and ASP.NET Core project using Visual Studio, follow the below steps:
+
+**Step 1: Install Syncfusion Package**
+
+Open your terminal in the project client folder and install the required Syncfusion packages using npm:
+
+```bash
+npm install @syncfusion/ej2-angular-grids --save
+npm install @syncfusion/ej2-data --save
+```
+
+**Step 2: Import Grid Module**
+
+In the `app.module.ts` file, import the **GridModule** from the `@syncfusion/ej2-angular-grids` package:
+
+**Step 3: Adding CSS reference**
+
+Include the necessary CSS files in your `styles.css` file to style the Syncfusion Angular Grid:
+
+{% tabs %}
+{% highlight css tabtitle="styles.css" %}
+
+ @import '../node_modules/@syncfusion/ej2-base/styles/material.css';
+ @import '../node_modules/@syncfusion/ej2-buttons/styles/material.css';
+ @import '../node_modules/@syncfusion/ej2-calendars/styles/material.css';
+ @import '../node_modules/@syncfusion/ej2-dropdowns/styles/material.css';
+ @import '../node_modules/@syncfusion/ej2-inputs/styles/material.css';
+ @import '../node_modules/@syncfusion/ej2-navigations/styles/material.css';
+ @import '../node_modules/@syncfusion/ej2-popups/styles/material.css';
+ @import '../node_modules/@syncfusion/ej2-splitbuttons/styles/material.css';
+ @import '../node_modules/@syncfusion/ej2-angular-grids/styles/material.css';
+
+{% endhighlight %}
+{% endtabs %}
+
+**2.** In your component file (e.g., **app.component.ts**), import `DataManager` and `UrlAdaptor` from `@syncfusion/ej2-data`. Create a [DataManager](https://ej2.syncfusion.com/angular/documentation/data/getting-started) instance specifying the URL of your API endpoint(https:localhost:xxxx/api/grid) using the `url` property and set the adaptor `UrlAdaptor`.
+
+**3.** The `DataManager` offers multiple adaptor options to connect with remote database based on an API service. Below is an example of the `UrlAdaptor` configuration where an API service are set up to return the resulting data in the `result` and `count` format.
+
+**4.** The `UrlAdaptor` acts as the base adaptor for interacting with remote data service. Most of the built-in adaptors are derived from the `UrlAdaptor`.
+
+{% tabs %}
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
+import { GridComponent, GridModule } from '@syncfusion/ej2-angular-grids';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new UrlAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+
+{% highlight cs tabtitle="GridController.cs" %}
+
+using Microsoft.AspNetCore.Mvc;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Data;
+using Syncfusion.EJ2.Base;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Internal;
+
+namespace Grid_EntityFramework.Server.Controllers
+{
+ [ApiController]
+ public class GridController : ControllerBase
+ {
+ string ConnectionString = @"";
+
+ ///
+ /// Processes the DataManager request to perform searching, filtering, sorting, and paging operations.
+ ///
+ /// Contains the details of the data operation requested.
+ /// Returns a JSON object along with the total record count.
+ [HttpPost]
+ [Route("api/[controller]")]
+ public object Post([FromBody] DataManagerRequest DataManagerRequest)
+ {
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+ }
+
+ ///
+ /// Retrieves the order data from the database.
+ ///
+ /// Returns a list of orders fetched from the database.
+ [HttpGet]
+ [Route("api/[controller]")]
+ public List GetOrderData()
+ {
+ using (OrderDbContext Context = new OrderDbContext(ConnectionString))
+ {
+ // Retrieve orders from the orders DbSet and convert to list asynchronously.
+ List orders = Context.Orders.ToList();
+ return orders;
+ }
+ }
+
+ // Create a class that inherits from DbContext(Entity Framework Core).
+ public class OrderDbContext : DbContext
+ {
+ //Declare a private variable to store the connection string.
+ private readonly string _ConnectionString;
+
+ //Define a constructor that accepts a connection string.
+ public OrderDbContext(string ConnectionString)
+ {
+ //Store the provided connection string.
+ _ConnectionString = ConnectionString;
+ }
+
+ //Override the onConfiguring method to tell EF Core to use SQL server.
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ // Use the connection string to configure the database connection.
+ optionsBuilder.UseSqlServer(_ConnectionString);
+ }
+
+ // Define a DbSet to represent the orders table in the database.
+ public DbSet Orders { get; set; }
+ }
+
+ public class Orders
+ {
+ [Key]
+ public int? OrderID { get; set; }
+ public string? CustomerID { get; set; }
+ public int? EmployeeID { get; set; }
+ public decimal Freight { get; set; }
+ public string? ShipCity { get; set; }
+ }
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+> Replace https://localhost:xxxx/api/Grid with the actual **URL** of your API endpoint that provides the data in a consumable format (e.g., JSON).
+
+**5.** Run the application in Visual Studio. It will be accessible via a URL like **https://localhost:xxxx**.
+
+> Ensure your API service is configured to handle CORS (Cross-Origin Resource Sharing), if necessary.
+
+ ```cs
+ [program.cs]
+ builder.Services.AddCors(options =>
+ {
+ options.AddDefaultPolicy(builder =>
+ {
+ builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
+ });
+ });
+ var app = builder.Build();
+ app.UseCors();
+ ```
+
+> * The Syncfusion Angular Grid provides built-in support for handling various data operations such as searching, sorting, filtering, aggregate and paging on the server-side. These operations can be handled using methods such as `PerformSearching`, `PerformFiltering`, `PerformSorting`, `PerformTake` and `PerformSkip` available in the [Syncfusion.EJ2.AspNet.Core](https://www.nuget.org/packages/Syncfusion.EJ2.AspNet.Core/) package. Let’s explore how to manage these data operations using the `UrlAdaptor`.
+> * In an API service project, add `Syncfusion.EJ2.AspNet.Core` by opening the NuGet package manager in Visual Studio (Tools → NuGet Package Manager → Manage NuGet Packages for Solution), search and install it.
+> * To access `DataManagerRequest` and `QueryableOperation`, import `Syncfusion.EJ2.Base` in `GridController.cs` file.
+
+### Handling searching operation
+
+To handle searching operation, ensure that your API endpoint supports custom searching criteria. Implement the searching logic on the server-side using the `PerformSearching` method from the `QueryableOperation` class. This allows the custom data source to undergo searching based on the criteria specified in the incoming `DataManagerRequest` object.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform searching operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the searched data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Handling searching operation.
+ if(DataManagerRequest.Search != null && DataManagerRequest.Search.Count > 0)
+ {
+ DataSource = queryableOperation.PerformSearching(DataSource, DataManagerRequest.Search);
+ //Add custom logic here if needed and remove above method.
+ }
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
+import { GridComponent, ToolbarItems, GridModule, ToolbarService } from '@syncfusion/ej2-angular-grids';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [ToolbarService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new UrlAdaptor()
+ });
+ this.toolbar = ['Search'];
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling filtering operation
+
+To handle filtering operation, ensure that your API endpoint supports custom filtering criteria. Implement the filtering logic on the server-side using the `PerformFiltering` method from the `QueryableOperation` class. This allows the custom data source to undergo filtering based on the criteria specified in the incoming `DataManagerRequest` object.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform filtering operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the filtered data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Handling filtering operation.
+ if (DataManagerRequest.Where != null && DataManagerRequest.Where.Count > 0)
+ {
+ foreach (WhereFilter condition in DataManagerRequest.Where)
+ {
+ foreach (WhereFilter predicate in condition.predicates)
+ {
+ DataSource = queryableOperation.PerformFiltering(DataSource, DataManagerRequest.Where, predicate.Operator);
+ //Add custom logic here if needed and remove above method.
+ }
+ }
+ }
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
+import { GridComponent, FilterService, GridModule } from '@syncfusion/ej2-angular-grids';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [FilterService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new UrlAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling sorting operation
+
+To handle sorting operation, ensure that your API endpoint supports custom sorting criteria. Implement the sorting logic on the server-side using the `PerformSorting` method from the `QueryableOperation` class. This allows the custom data source to undergo sorting based on the criteria specified in the incoming `DataManagerRequest` object.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform sorting operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the sorted data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Handling sorting operation.
+ if(DataManagerRequest.Sorted != null && DataManagerRequest.Sorted.Count > 0)
+ {
+ DataSource = queryableOperation.PerformSorting(DataSource, DataManagerRequest.Sorted);
+ //Add custom logic here if needed and remove above method.
+ }
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
+import { GridComponent, SortService, GridModule } from '@syncfusion/ej2-angular-grids';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [SortService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new UrlAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling paging operation
+
+To handle paging operation, ensure that your API endpoint supports custom paging criteria. Implement the paging logic on the server-side using the `PerformTake` and `PerformSkip` method from the `QueryableOperation` class. This allows the custom data source to undergo paging based on the criteria specified in the incoming `DataManagerRequest` object.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform paging operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the paginated data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Handling paging operation.
+ if (DataManagerRequest.Skip != 0)
+ {
+ DataSource = queryableOperation.PerformSkip(DataSource, DataManagerRequest.Skip);
+ //Add custom logic here if needed and remove above method.
+ }
+ if (DataManagerRequest.Take != 0)
+ {
+ DataSource = queryableOperation.PerformTake(DataSource, DataManagerRequest.Take);
+ //Add custom logic here if needed and remove above method.
+ }
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
+import { GridComponent, PageService, GridModule } from '@syncfusion/ej2-angular-grids';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [PageService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new UrlAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling CRUD operations
+
+The Syncfusion Angular Grid seamlessly integrates CRUD (Create, Read, Update, and Delete) operations with server-side controller actions through specific properties: `insertUrl`, `removeUrl`, `updateUrl` and `batchUrl`. These properties enable the Grid to communicate with the data service for every Grid action, facilitating server-side operations.
+
+**CRUD Operations Mapping**
+
+CRUD operations within the Grid can be mapped to server-side controller actions using specific properties:
+
+1. **insertUrl**: Specifies the URL for inserting new data.
+2. **removeUrl**: Specifies the URL for removing existing data.
+3. **updateUrl**: Specifies the URL for updating existing data.
+4. **batchUrl**: Specifies the URL for batch editing.
+
+To enable editing in Grid, refer to the editing [documentation](https://ej2.syncfusion.com/angular/documentation/grid/editing/edit). In the below example, the inline edit [mode](https://ej2.syncfusion.com/angular/documentation/api/grid/editSettings/#mode) is enabled and [toolbar](https://helpej2.syncfusion.com/angular/documentation/api/grid/#toolbar) property is configured to display toolbar items for editing purposes.
+
+{% tabs %}
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
+import { GridComponent, EditSettingsModel,GridModule, ToolbarItems,EditService, ToolbarService } from '@syncfusion/ej2-angular-grids';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [EditService, ToolbarService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+ public editSettings?: EditSettingsModel;
+ public toolbar?: ToolbarItems[];
+ public employeeIDRules?: Object;
+ public customerIDRules?: Object;
+ public freightRules?: Object;
+ public shipCityRules?: Object;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ insertUrl: 'https://localhost:xxxx/api/Grid/Insert',
+ updateUrl: 'https://localhost:xxxx/api/Grid/Update',
+ removeUrl: 'https://localhost:xxxx/api/Grid/Remove',
+ // Enable batch URL when batch editing is enabled.
+ //batchUrl: 'https://localhost:xxxx/api/Grid/BatchUpdate',
+ adaptor: new UrlAdaptor()
+ });
+ this.employeeIDRules = { required: true, number: true };
+ this.customerIDRules = { required: true };
+ this.freightRules = { required: true, min: 1, max: 1000 };
+ this.shipCityRules = { required: true };
+ this.toolbar = ['Add', 'Update', 'Delete', 'Cancel', 'Search'];
+ this.editSettings = { allowAdding: true, allowDeleting: true, allowEditing: true, mode: 'Normal' };
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+{% endtabs %}
+
+> * Normal/Inline editing is the default edit [mode](https://ej2.syncfusion.com/angular/documentation/api/grid/editSettings/#mode) for the Grid. To enable CRUD operations, ensure that the [isPrimaryKey](https://ej2.syncfusion.com/angular/documentation/api/grid/column/#isprimarykey) property is set to **true** for a specific Grid column, ensuring that its value is unique.
+> * If database has an auto generated column, ensure to define [isIdentity](https://ej2.syncfusion.com/angular/documentation/api/grid/column/#isidentity) property of Grid column to disable them during adding or editing operations.
+
+**Insert Operation:**
+
+To insert a new row, simply click the **Add** toolbar button. The new record edit form will be displayed as shown below. Upon clicking the **Update** toolbar button, record will inserted into the **Orders** table by calling the following **POST** method of an API. Utilizing `Entity Framework` simplifies database tasks by managing database connections and queries through object-oriented programming, making it easier to work with databases in C# code, as shown in the following code snippet.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Inserts a new data item into the data collection.
+///
+/// It contains the new record detail which is need to be inserted.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/Insert")]
+public void Insert([FromBody] CRUDModel value)
+{
+ using (OrderDbContext Context = new OrderDbContext(ConnectionString))
+ {
+ // Add the provided order to the orders DbSet.
+ Context.Orders.Add(value.value);
+
+ // Save changes to the database.
+ Context.SaveChanges();
+ }
+
+ //Add custom logic here if needed and remove above method.
+}
+
+// Create a class that inherits from DbContext(Entity Framework Core).
+public class OrderDbContext : DbContext
+{
+ //Declare a private variable to store the connection string.
+ private readonly string _ConnectionString;
+
+ //Define a constructor that accepts a connection string.
+ public OrderDbContext(string ConnectionString)
+ {
+ //Store the provided connection string.
+ _ConnectionString = ConnectionString;
+ }
+
+ //Override the onConfiguring method to tell EF Core to use SQL server.
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ // Use the connection string to configure the database connection.
+ optionsBuilder.UseSqlServer(_ConnectionString);
+ }
+
+ // Define a DbSet to represent the orders table in the database.
+ public DbSet Orders { get; set; }
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**Update Operation:**
+
+To edit a row, first select desired row and click the **Edit** toolbar button. The edit form will be displayed and proceed to modify any column value as per your requirement. Clicking the **Update** toolbar button will update the edit record in the **Orders** table by involving the following **Post** method of an API. Utilizing `Entity Framework` simplifies database tasks by managing database connections and queries through object-oriented programming, making it easier to work with databases in C# code, as shown in the following code snippet.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Update a existing data item from the data collection.
+///
+/// It contains the updated record detail which is need to be updated.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/Update")]
+public void Update([FromBody] CRUDModel value)
+{
+ using (OrderDbContext Context = new OrderDbContext(ConnectionString))
+ {
+ Orders existingOrder = Context.Orders.Find(value.value.OrderID);
+ if (existingOrder != null)
+ {
+ // Update the existing order with the new values.
+ Context.Entry(existingOrder).CurrentValues.SetValues(value.value);
+
+ // Save changes to the database.
+ Context.SaveChanges();
+ }
+ }
+
+ //Add custom logic here if needed and remove above method.
+}
+
+// Create a class that inherits from DbContext(Entity Framework Core).
+public class OrderDbContext : DbContext
+{
+ //Declare a private variable to store the connection string.
+ private readonly string _ConnectionString;
+
+ //Define a constructor that accepts a connection string.
+ public OrderDbContext(string ConnectionString)
+ {
+ //Store the provided connection string.
+ _ConnectionString = ConnectionString;
+ }
+
+ //Override the onConfiguring method to tell EF Core to use SQL server.
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ // Use the connection string to configure the database connection.
+ optionsBuilder.UseSqlServer(_ConnectionString);
+ }
+
+ // Define a DbSet to represent the orders table in the database.
+ public DbSet Orders { get; set; }
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**Delete Operation:**
+
+To delete a row, simply select the desired row and click the **Delete** toolbar button. This action will trigger a **DELETE** request to an API, containing the primary key value of the selected record. As a result corresponding record will be removed from the **Orders** table. Utilizing `Entity Framework` simplifies database tasks by managing database connections and queries through object-oriented programming, making it easier to work with databases in C# code, as shown in the following code snippet.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Remove a specific data item from the data collection.
+///
+/// It contains the specific record detail which is need to be removed.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/Remove")]
+public void Remove([FromBody] CRUDModel value)
+{
+ int OrderId = Convert.ToInt32(value.key.ToString());
+ using (OrderDbContext Context = new OrderDbContext(ConnectionString))
+ {
+ Orders Order = Context.Orders.Find(OrderId);
+ if (Order != null)
+ {
+ // Remove the order from the orders DbSet.
+ Context.Orders.Remove(Order);
+
+ // Save changes to the database.
+ Context.SaveChanges();
+ }
+ }
+
+ //Add custom logic here if needed and remove above method.
+}
+
+// Create a class that inherits from DbContext(Entity Framework Core).
+public class OrderDbContext : DbContext
+{
+ //Declare a private variable to store the connection string.
+ private readonly string _ConnectionString;
+
+ //Define a constructor that accepts a connection string.
+ public OrderDbContext(string ConnectionString)
+ {
+ //Store the provided connection string.
+ _ConnectionString = ConnectionString;
+ }
+
+ //Override the onConfiguring method to tell EF Core to use SQL server.
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ // Use the connection string to configure the database connection.
+ optionsBuilder.UseSqlServer(_ConnectionString);
+ }
+
+ // Define a DbSet to represent the orders table in the database.
+ public DbSet Orders { get; set; }
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**Batch Operation:**
+
+To perform batch operation, define the edit [mode](https://ej2.syncfusion.com/angular/documentation/api/grid/editSettings/#mode) as **Batch** and specify the `batchUrl` property in the `DataManager`. Use the **Add** toolbar button to insert new row in batch editing mode. To edit a cell, double-click the desired cell and update the value as required. To delete a record, simply select the record and press the **Delete** toolbar button. Now, all CRUD operations will be executed in batch editing mode. Clicking the **Update** toolbar button will update the newly added, edited, or deleted records from the **Orders** table using a single API **POST** request.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Batch update (Insert, Update, and Delete) a collection of data items from the data collection.
+///
+/// The set of information along with details about the CRUD actions to be executed from the database.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/BatchUpdate")]
+public IActionResult BatchUpdate([FromBody] CRUDModel value)
+{
+ using (OrderDbContext Context = new OrderDbContext(ConnectionString))
+ {
+ if (value.changed != null && value.changed.Count > 0)
+ {
+ foreach (Orders Record in (IEnumerable)value.changed)
+ {
+ // Update the changed records.
+ Context.Orders.UpdateRange(Record);
+ }
+ }
+
+ if (value.added != null && value.added.Count > 0)
+ {
+ foreach (Orders Record in (IEnumerable)value.added)
+ {
+ foreach (Orders order in value.added)
+ {
+ // This ensures EF does not try to insert OrderID.
+ order.OrderID = default;
+ }
+ // Add new records.
+ Context.Orders.AddRange(value.added);
+ }
+ }
+
+ if (value.deleted != null && value.deleted.Count > 0)
+ {
+ foreach (Orders Record in (IEnumerable)value.deleted)
+ {
+ // Find and delete the records.
+ Orders ExistingOrder = Context.Orders.Find(Record.OrderID);
+ if (ExistingOrder != null)
+ {
+ Context.Orders.Remove(ExistingOrder);
+ }
+ }
+ }
+
+ // Save changes to the database.
+ Context.SaveChanges();
+ }
+ return new JsonResult(value);
+}
+
+// Create a class that inherits from DbContext(Entity Framework Core).
+public class OrderDbContext : DbContext
+{
+ //Declare a private variable to store the connection string.
+ private readonly string _ConnectionString;
+
+ //Define a constructor that accepts a connection string.
+ public OrderDbContext(string ConnectionString)
+ {
+ //Store the provided connection string.
+ _ConnectionString = ConnectionString;
+ }
+
+ //Override the onConfiguring method to tell EF Core to use SQL server.
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ // Use the connection string to configure the database connection.
+ optionsBuilder.UseSqlServer(_ConnectionString);
+ }
+
+ // Define a DbSet to represent the orders table in the database.
+ public DbSet Orders { get; set; }
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+When you run the application, the resultant Syncfusion Angular Grid will look like this
+
+
+
+> Please find the sample in this [GitHub location](https://github.com/SyncfusionExamples/connecting-databases-to-angular-grid/tree/master/Bindind%20SQL%20database%20using%20EF%20and%20UrlAdaptor/Grid_EntityFramework).
+
+## Binding data from Microsoft SQL Server using Entity Framework with CustomAdaptor
+
+This section describes step by step process how to use Entity Framework to retrieve data from a Microsoft SQL Server using [CustomAdaptor](https://ej2.syncfusion.com/angular/documentation/grid/connecting-to-adaptors/custom-adaptor) and bind it to the Syncfusion Angular Grid.
+
+**1.** To create a simple Grid, the procedure is explained in the above-mentioned topic on [Connecting Syncfusion Angular Grid to an API service](#connecting-syncfusion-angular-grid-to-an-api-service)
+
+**2.** To use `Entity Framework` and access the Microsoft SQL Server database in our Angular application, we need to install the [Microsoft.EntityFrameworkCore](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore) and [Microsoft.EntityFrameworkCore.SqlServer ](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.SqlServer/) NuGet packages. To add **Microsoft.EntityFrameworkCore** and **Microsoft.EntityFrameworkCore.SqlServer** in the app, open the NuGet package manager in Visual Studio (Tools → NuGet Package Manager → Manage NuGet Packages for Solution), search and install it.
+
+**3.** If you intend to inject your own service into the `CustomAdaptor` and utilize it, you can achieve this as follows:
+
+ * Create a `CustomAdaptor` that extends the `UrlAdaptor` class.
+ * Override the `processResponse` method to process server responses.
+
+**4.** Within the `processResponse` method of `CustomAdaptor`, fetch data by calling the **GetOrderData** method.
+
+ * In this **GetOrderData** method, a connection is established to Microsoft SQL Server using **OrderDbContext**. This class extends **DbContext** and is configured to connect to a SQL Server database using the provided connection string. It includes a *DbSet<Orders>** property, enabling interaction with the **Orders** table in the database. The method retrieves all orders from the database asynchronously and returns them as a list of `Orders` objects.
+
+ * Finally, return the response as a `result` and `count` pair object in the `processResponse` method to bind the data to the Grid.
+
+{% tabs %}
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager } from '@syncfusion/ej2-data';
+import { GridComponent, GridModule } from '@syncfusion/ej2-angular-grids';
+import { CustomAdaptor } from './CustomAdaptor'
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid',
+ adaptor: new CustomAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="CustomAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+}
+
+{% endhighlight %}
+
+{% highlight cs tabtitle="GridController.cs" %}
+
+using Microsoft.AspNetCore.Mvc;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Data;
+using Syncfusion.EJ2.Base;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Internal;
+
+namespace Grid_EntityFramework.Server.Controllers
+{
+ [ApiController]
+ public class GridController : ControllerBase
+ {
+ string ConnectionString = @"";
+
+ ///
+ /// Processes the DataManager request to perform searching, filtering, sorting, and paging operations.
+ ///
+ /// Contains the details of the data operation requested.
+ /// Returns a JSON object along with the total record count.
+ [HttpPost]
+ [Route("api/[controller]")]
+ public object Post([FromBody] DataManagerRequest DataManagerRequest)
+ {
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+ }
+
+ ///
+ /// Retrieves the order data from the database.
+ ///
+ /// Returns a list of orders fetched from the database.
+ [HttpGet]
+ [Route("api/[controller]")]
+ public List GetOrderData()
+ {
+ using (OrderDbContext Context = new OrderDbContext(ConnectionString))
+ {
+ // Retrieve orders from the orders DbSet and convert to list asynchronously.
+ List orders = Context.Orders.ToList();
+ return orders;
+ }
+ }
+
+ // Create a class that inherits from DbContext(Entity Framework Core).
+ public class OrderDbContext : DbContext
+ {
+ //Declare a private variable to store the connection string.
+ private readonly string _ConnectionString;
+
+ //Define a constructor that accepts a connection string.
+ public OrderDbContext(string ConnectionString)
+ {
+ //Store the provided connection string.
+ _ConnectionString = ConnectionString;
+ }
+
+ //Override the onConfiguring method to tell EF Core to use SQL server.
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ // Use the connection string to configure the database connection.
+ optionsBuilder.UseSqlServer(_ConnectionString);
+ }
+
+ // Define a DbSet to represent the orders table in the database.
+ public DbSet Orders { get; set; }
+ }
+
+ public class Orders
+ {
+ [Key]
+ public int? OrderID { get; set; }
+ public string? CustomerID { get; set; }
+ public int? EmployeeID { get; set; }
+ public decimal Freight { get; set; }
+ public string? ShipCity { get; set; }
+ }
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+> * The `DataManagerRequest` encompasses details about the Grid actions such as searching, filtering, sorting, aggregate, paging and grouping.
+
+### Handling searching operation
+
+When utilizing the `CustomAdaptor` in Angular, managing the searching operation involves overriding the `processResponse` method of the `UrlAdaptor` class.
+
+In the code example below, searching a custom data source can be accomplished by employing the built-in `PerformSearching` method of the `QueryableOperation` class. Alternatively, you can implement your own method for searching operation and bind the resultant data to the Syncfusion Angular Grid.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform searching operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the searched data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Handling searching operation.
+ if (DataManagerRequest.Search != null && DataManagerRequest.Search.Count > 0)
+ {
+ DataSource = queryableOperation.PerformSearching(DataSource, DataManagerRequest.Search);
+ //Add custom logic here if needed and remove above method.
+ }
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager } from '@syncfusion/ej2-data';
+import { GridComponent, ToolbarItems, ToolbarService, GridModule} from '@syncfusion/ej2-angular-grids';
+import { CustomAdaptor } from './CustomAdaptor'
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [ToolbarService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+ public toolbar?: ToolbarItems[];
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new CustomAdaptor()
+ });
+ this.toolbar = ['Search'];
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="customAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling filtering operation
+
+When utilizing the `CustomAdaptor` in Angular, managing the filtering operation involves overriding the `processResponse` method of the `UrlAdaptor` class.
+
+In the code example below, filtering a custom data source can be achieved by utilizing the built-in `PerformFiltering` method of the `QueryableOperation` class. Alternatively, you can implement your own method for filtering operation and bind the resulting data to the Syncfusion Angular Grid.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform filtering operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the filtered data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Handling filtering operation.
+ if (DataManagerRequest.Where != null && DataManagerRequest.Where.Count > 0)
+ {
+ foreach (WhereFilter condition in DataManagerRequest.Where)
+ {
+ foreach (WhereFilter predicate in condition.predicates)
+ {
+ DataSource = queryableOperation.PerformFiltering(DataSource, DataManagerRequest.Where, predicate.Operator);
+ //Add custom logic here if needed and remove above method.
+ }
+ }
+ }
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager } from '@syncfusion/ej2-data';
+import { GridComponent, FilterService, GridModule } from '@syncfusion/ej2-angular-grids';
+import { CustomAdaptor } from './CustomAdaptor'
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [FilterService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid')public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new CustomAdaptor()
+ });
+ }
+}
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="customAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling sorting operation
+
+When utilizing the `CustomAdaptor` in Angular, managing the sorting operation involves overriding the `processResponse` method of the `UrlAdaptor` class.
+
+In the code example below, sorting a custom data source can be accomplished by employing the built-in `PerformSorting` method of the `QueryableOperation` class. Alternatively, you can implement your own method for sorting operation and bind the resulting data to the Syncfusion Angular Grid.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform sorting operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the sorted data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Handling sorting operation.
+ if (DataManagerRequest.Sorted != null && DataManagerRequest.Sorted.Count > 0)
+ {
+ DataSource = queryableOperation.PerformSorting(DataSource, DataManagerRequest.Sorted);
+ //Add custom logic here if needed and remove above method.
+ }
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager } from '@syncfusion/ej2-data';
+import { GridComponent, SortService, GridModule } from '@syncfusion/ej2-angular-grids';
+import { CustomAdaptor } from './CustomAdaptor'
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [SortService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new CustomAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="customAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling paging operation
+
+When utilizing the `CustomAdaptor` in Angular, managing the paging operation involves overriding the `processResponse` method of the `UrlAdaptor` class.
+
+In the code example below, paging a custom data source can be achieved by utilizing the built-in `PerformTake` and `PerformSkip` method of the `QueryableOperation` class. Alternatively, you can use your own method for paging operation and bind the resulting data to the Syncfusion Angular Grid.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform paging operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the paginated data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Handling paging operation.
+ if (DataManagerRequest.Skip != 0)
+ {
+ DataSource = queryableOperation.PerformSkip(DataSource, DataManagerRequest.Skip);
+ //Add custom logic here if needed and remove above method.
+ }
+ if (DataManagerRequest.Take != 0)
+ {
+ DataSource = queryableOperation.PerformTake(DataSource, DataManagerRequest.Take);
+ //Add custom logic here if needed and remove above method.
+ }
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager } from '@syncfusion/ej2-data';
+import { GridComponent, PageService, GridModule } from '@syncfusion/ej2-angular-grids';
+import { CustomAdaptor } from './CustomAdaptor'
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [PageService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new CustomAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="customAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling CRUD operations
+
+To enable editing in the Syncfusion Angular Grid, utilize the [editSettings](https://ej2.syncfusion.com/angular/documentation/api/grid/editSettings/) property. The Grid offers multiple edit modes including the **Inline/Normal**, **Dialog** and **Batch** editing. For more details, refer to the Grid [editing](https://ej2.syncfusion.com/angular/documentation/grid/editing/edit) documentation.
+
+In this scenario, the inline edit `mode` and [toolbar](https://ej2.syncfusion.com/angular/documentation/api/grid/#toolbar) property configured to display toolbar items for editing purpose.
+
+{% tabs %}
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager } from '@syncfusion/ej2-data';
+import { GridComponent, EditSettingsModel, ToolbarItems,EditService, ToolbarService,GridModule } from '@syncfusion/ej2-angular-grids';
+import { CustomAdaptor } from './CustomAdaptor'
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [EditService, ToolbarService ],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+ public editSettings?: EditSettingsModel;
+ public toolbar?: ToolbarItems[];
+ public employeeIDRules?: Object;
+ public customerIDRules?: Object;
+ public freightRules?: Object;
+ public shipCityRules?: Object;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid',
+ insertUrl: 'https://localhost:xxxx/api/Grid/Insert',
+ updateUrl: 'https://localhost:xxxx/api/Grid/Update',
+ removeUrl: 'https://localhost:xxxx/api/Grid/Remove',
+ // Enable batch URL when batch editing is enabled.
+ //batchUrl: 'https://localhost:xxxx/api/Grid/BatchUpdate',
+ adaptor: new CustomAdaptor()
+ });
+ this.employeeIDRules = { required: true, number: true };
+ this.customerIDRules = { required: true };
+ this.freightRules = { required: true, min: 1, max: 1000 };
+ this.shipCityRules = { required: true };
+ this.toolbar = ['Add', 'Update', 'Delete', 'Cancel', 'Search'];
+ this.editSettings = { allowAdding: true, allowDeleting: true, allowEditing: true, mode: 'Normal' };
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+{% endtabs %}
+
+> * Normal/Inline editing is the default edit [mode](https://ej2.syncfusion.com/angular/documentation/api/grid/editSettings/#mode) for the Grid. To enable CRUD operations, ensure that the [isPrimaryKey](https://ej2.syncfusion.com/angular/documentation/api/grid/column/#isprimarykey) property is set to **true** for a specific Grid column, ensuring that its value is unique.
+> * If database has an auto generated column, ensure to define [isIdentity](https://ej2.syncfusion.com/angular/documentation/api/grid/column/#isidentity) property of Grid column to disable them during adding or editing operations.
+
+The CRUD operations can be performed and customized on our own by overriding the following CRUD methods of the `UrlAdaptor`
+
+* insert
+* remove
+* update
+* batchRequest
+
+Let’s see how to perform CRUD operations using Entity Framework in Microsoft SQL Server data with Syncfusion Angular Grid.
+
+**Insert Operation:**
+
+To execute the insert operation, you will need to override the `insert` method of the `CustomAdaptor`. Then, integrate the following code snippet into the `CustomAdaptor` class. The below code snippet demonstrated how to handle the insertion of new records within the `insert` method of `CustomAdaptor` . Modify the logic within this method according to the requirements of your application. Utilizing `Entity Framework` simplifies database tasks by managing database connections and queries through object-oriented programming, making it easier to work with databases in C# code, as shown in the following code snippet.
+
+{% tabs %}
+{% highlight ts tabtitle="CustomAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+
+ public override insert(dm: any, data: any): any {
+ return {
+ url: dm.dataSource.insertUrl || dm.dataSource.url,
+ data: JSON.stringify({
+ __RequestVerificationToken: "Syncfusion",
+ value: data,
+ action: 'insert'
+ }),
+ type: 'POST'
+ };
+ }
+}
+{% endhighlight %}
+
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Inserts a new data item into the data collection.
+///
+/// It contains the new record detail which is need to be inserted.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/Insert")]
+public void Insert([FromBody] CRUDModel value)
+{
+ using (OrderDbContext Context = new OrderDbContext(ConnectionString))
+ {
+ // Add the provided order to the orders DbSet.
+ Context.Orders.Add(value.value);
+
+ // Save changes to the database.
+ Context.SaveChanges();
+ }
+
+ //Add custom logic here if needed and remove above method.
+}
+
+// Create a class that inherits from DbContext(Entity Framework Core).
+public class OrderDbContext : DbContext
+{
+ //Declare a private variable to store the connection string.
+ private readonly string _ConnectionString;
+
+ //Define a constructor that accepts a connection string.
+ public OrderDbContext(string ConnectionString)
+ {
+ //Store the provided connection string.
+ _ConnectionString = ConnectionString;
+ }
+
+ //Override the onConfiguring method to tell EF Core to use SQL server.
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ // Use the connection string to configure the database connection.
+ optionsBuilder.UseSqlServer(_ConnectionString);
+ }
+
+ // Define a DbSet to represent the orders table in the database.
+ public DbSet Orders { get; set; }
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**Update Operation:**
+
+To execute the update operation, override the `update` method of the `CustomAdaptor`. Then, integrate the following code snippet into the `CustomAdaptor` class. The below code snippet demonstrated how to handle the updating of existing records within the `update` method of the `CustomAdaptor`. Modify the logic within this method according to the requirements of your application. Utilizing `Entity Framework` simplifies database tasks by managing database connections and queries through object-oriented programming, making it easier to work with databases in C# code, as shown in the following code snippet.
+
+{% tabs %}
+{% highlight ts tabtitle="CustomAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+
+ public override update(dm: any, keyField: string, value: any): any {
+ return {
+ url: dm.dataSource.updateUrl || dm.dataSource.url,
+ data: JSON.stringify({
+ __RequestVerificationToken: "Syncfusion",
+ value: value,
+ action: 'update'
+ }),
+ type: 'POST'
+ };
+ }
+}
+
+{% endhighlight %}
+
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Update a existing data item from the data collection.
+///
+/// It contains the updated record detail which is need to be updated.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/Update")]
+public void Update([FromBody] CRUDModel value)
+{
+ using (OrderDbContext Context = new OrderDbContext(ConnectionString))
+ {
+ Orders existingOrder = Context.Orders.Find(value.value.OrderID);
+ if (existingOrder != null)
+ {
+ // Update the existing order with the new values.
+ Context.Entry(existingOrder).CurrentValues.SetValues(value.value);
+
+ // Save changes to the database.
+ Context.SaveChanges();
+ }
+ }
+
+ //Add custom logic here if needed and remove above method.
+}
+
+// Create a class that inherits from DbContext(Entity Framework Core).
+public class OrderDbContext : DbContext
+{
+ //Declare a private variable to store the connection string.
+ private readonly string _ConnectionString;
+
+ //Define a constructor that accepts a connection string.
+ public OrderDbContext(string ConnectionString)
+ {
+ //Store the provided connection string.
+ _ConnectionString = ConnectionString;
+ }
+
+ //Override the onConfiguring method to tell EF Core to use SQL server.
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ // Use the connection string to configure the database connection.
+ optionsBuilder.UseSqlServer(_ConnectionString);
+ }
+
+ // Define a DbSet to represent the orders table in the database.
+ public DbSet Orders { get; set; }
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**Delete Operation:**
+
+To perform the delete operation, you need to override the `remove` method of the `CustomAdaptor`. Below is the code snippet that you can add to `CustomAdaptor` class. The below code snippet demonstrated how to handle the deletion of existing records within the `remove` method of `CustomAdaptor`. Modify the logic within this method according to the requirements of your application. Utilizing `Entity Framework` simplifies database tasks by managing database connections and queries through object-oriented programming, making it easier to work with databases in C# code, as shown in the following code snippet.
+
+{% tabs %}
+{% highlight ts tabtitle="CustomAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+
+ public override remove(dm: any, keyField: string, value: any): any {
+ return {
+ url: dm.dataSource.removeUrl || dm.dataSource.url,
+ data: JSON.stringify({
+ __RequestVerificationToken: "Syncfusion",
+ key: value,
+ keyColumn: keyField,
+ action: 'remove'
+ }),
+ type: 'POST'
+ };
+ }
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="GridController.cs" %}
+
+///
+/// Remove a specific data item from the data collection.
+///
+/// It contains the specific record detail which is need to be removed.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/Remove")]
+public void Remove([FromBody] CRUDModel value)
+{
+ int OrderId = Convert.ToInt32(value.key.ToString());
+ using (OrderDbContext Context = new OrderDbContext(ConnectionString))
+ {
+ Orders Order = Context.Orders.Find(OrderId);
+ if (Order != null)
+ {
+ // Remove the order from the orders DbSet.
+ Context.Orders.Remove(Order);
+
+ // Save changes to the database.
+ Context.SaveChanges();
+ }
+ }
+
+ //Add custom logic here if needed and remove above method.
+}
+
+// Create a class that inherits from DbContext(Entity Framework Core).
+public class OrderDbContext : DbContext
+{
+ //Declare a private variable to store the connection string.
+ private readonly string _ConnectionString;
+
+ //Define a constructor that accepts a connection string.
+ public OrderDbContext(string ConnectionString)
+ {
+ //Store the provided connection string.
+ _ConnectionString = ConnectionString;
+ }
+
+ //Override the onConfiguring method to tell EF Core to use SQL server.
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ // Use the connection string to configure the database connection.
+ optionsBuilder.UseSqlServer(_ConnectionString);
+ }
+
+ // Define a DbSet to represent the orders table in the database.
+ public DbSet Orders { get; set; }
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**Batch Operation:**
+
+To perform the batch operation, override the `batchRequest` method of the `CustomAdaptor` and add the following code in the `CustomAdaptor`. The below code snippet demonstrated how to handle the batch update request within the `batchRequest` method of `CustomAdaptor`. Modify the logic within this method according to the requirements of your application.
+
+{% tabs %}
+{% highlight ts tabtitle="CustomAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+
+ public override batchRequest(dm:any, changes: any, e:any, query: any, original?: Object): Object {
+ return {
+ url: dm.dataSource.batchUrl || dm.dataSource.url,
+ data: JSON.stringify({
+ __RequestVerificationToken: "Syncfusion",
+ added: changes.addedRecords,
+ changed: changes.changedRecords,
+ deleted: changes.deletedRecords,
+ key: e.key,
+ action: 'batch'
+ }),
+ type: 'POST'
+ };
+ }
+}
+
+{% endhighlight %}
+
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Batch update (Insert, Update, and Delete) a collection of data items from the data collection.
+///
+/// The set of information along with details about the CRUD actions to be executed from the database.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/BatchUpdate")]
+public IActionResult BatchUpdate([FromBody] CRUDModel value)
+{
+ using (OrderDbContext Context = new OrderDbContext(ConnectionString))
+ {
+ if (value.changed != null && value.changed.Count > 0)
+ {
+ foreach (Orders Record in (IEnumerable)value.changed)
+ {
+ // Update the changed records.
+ Context.Orders.UpdateRange(Record);
+ }
+ }
+
+ if (value.added != null && value.added.Count > 0)
+ {
+ foreach (Orders Record in (IEnumerable)value.added)
+ {
+ foreach (Orders order in value.added)
+ {
+ // This ensures EF does not try to insert OrderID.
+ order.OrderID = default;
+ }
+ // Add new records.
+ Context.Orders.AddRange(value.added);
+ }
+ }
+
+ if (value.deleted != null && value.deleted.Count > 0)
+ {
+ foreach (Orders Record in (IEnumerable)value.deleted)
+ {
+ // Find and delete the records.
+ Orders ExistingOrder = Context.Orders.Find(Record.OrderID);
+ if (ExistingOrder != null)
+ {
+ Context.Orders.Remove(ExistingOrder);
+ }
+ }
+ }
+
+ // Save changes to the database.
+ Context.SaveChanges();
+ }
+ return new JsonResult(value);
+}
+
+// Create a class that inherits from DbContext(Entity Framework Core).
+public class OrderDbContext : DbContext
+{
+ //Declare a private variable to store the connection string.
+ private readonly string _ConnectionString;
+
+ //Define a constructor that accepts a connection string.
+ public OrderDbContext(string ConnectionString)
+ {
+ //Store the provided connection string.
+ _ConnectionString = ConnectionString;
+ }
+
+ //Override the onConfiguring method to tell EF Core to use SQL server.
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ // Use the connection string to configure the database connection.
+ optionsBuilder.UseSqlServer(_ConnectionString);
+ }
+
+ // Define a DbSet to represent the orders table in the database.
+ public DbSet Orders { get; set; }
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+
+
+> Please find the sample in this [GitHub location](https://github.com/SyncfusionExamples/connecting-databases-to-angular-grid/tree/master/Bindind%20SQL%20database%20using%20EF%20and%20CustomAdaptor/Grid_EntityFramework).
\ No newline at end of file
diff --git a/ej2-angular/grid/connecting-to-database/microsoft-sql-server.md b/ej2-angular/grid/connecting-to-database/microsoft-sql-server.md
index e32c1f206a..e6d1d271cb 100644
--- a/ej2-angular/grid/connecting-to-database/microsoft-sql-server.md
+++ b/ej2-angular/grid/connecting-to-database/microsoft-sql-server.md
@@ -951,6 +951,8 @@ When you run the application, the resultant Syncfusion Angular Grid will look li

+> Please find the sample in this [GitHub location](https://github.com/SyncfusionExamples/connecting-databases-to-angular-grid/tree/master/Binding%20MS%20SQL%20database%20using%20UrlAdaptor/Grid_MSSQL).
+
## Binding data from Microsoft SQL Server using CustomAdaptor
This section describes step by step process how to retrieve data from a Microsoft SQL Server using [CustomAdaptor](https://ej2.syncfusion.com/angular/documentation/grid/connecting-to-adaptors/custom-adaptor) and bind it to the Syncfusion Angular Grid.
@@ -1923,4 +1925,6 @@ public class CRUDModel where T : class
{% endhighlight %}
{% endtabs %}
-
\ No newline at end of file
+
+
+> Please find the sample in this [GitHub location](https://github.com/SyncfusionExamples/connecting-databases-to-angular-grid/tree/master/Binding%20MS%20SQL%20database%20using%20CustomAdaptor/Grid_MSSQL).
\ No newline at end of file
diff --git a/ej2-angular/grid/connecting-to-database/mysql-server.md b/ej2-angular/grid/connecting-to-database/mysql-server.md
index 23d35b4ba6..51253b4af0 100644
--- a/ej2-angular/grid/connecting-to-database/mysql-server.md
+++ b/ej2-angular/grid/connecting-to-database/mysql-server.md
@@ -1017,7 +1017,9 @@ public class CRUDModel where T : class
When you run the application, the resultant Syncfusion Angular Grid will look like this
-
+
+
+> Please find the sample in this [GitHub location](https://github.com/SyncfusionExamples/connecting-databases-to-angular-grid/tree/master/Binding%20MySQL%20database%20using%20UrlAdaptor/Grid_MySQL).
## Binding data from MySQL Server using CustomAdaptor
@@ -1899,7 +1901,7 @@ public class CRUDModel where T : class
{% endhighlight %}
{% endtabs %}
-## Batch Operation:
+**Batch Operation:**
To perform the batch operation, override the **batchRequest** method of the `CustomAdaptor` and add the following code in the `CustomAdaptor`. The below code snippet demonstrated how to handle the batch update request within the **batchRequest** method of `CustomAdaptor`. Modify the logic within this method according to the requirements of your application.
@@ -2037,4 +2039,6 @@ public class CRUDModel where T : class
{% endhighlight %}
{% endtabs %}
-
\ No newline at end of file
+
+
+> Please find the sample in this [GitHub location](https://github.com/SyncfusionExamples/connecting-databases-to-angular-grid/tree/master/Binding%20MySQL%20database%20using%20CustomAdaptor/Grid_MySQL).
\ No newline at end of file
diff --git a/ej2-angular/grid/connecting-to-database/postgresql-server.md b/ej2-angular/grid/connecting-to-database/postgresql-server.md
new file mode 100644
index 0000000000..f791a64e70
--- /dev/null
+++ b/ej2-angular/grid/connecting-to-database/postgresql-server.md
@@ -0,0 +1,2054 @@
+---
+layout: post
+title: PostgreSQL Server Data Binding Syncfusion Angular Grid
+description: Learn how to consume data from PostgreSQL Server, bind it to Syncfusion Angular Grid, and perform CRUD operations.
+platform: ej2-angular
+control: grid
+keywords: adaptors, customadaptor, urladaptor, postgresql, remotedata
+documentation: ug
+domainurl: ##DomainURL##
+---
+
+# Connecting PostgreSQL Server data to Syncfusion Angular Grid
+
+This section describes how to connect and retrieve data from a PostgreSQL Server database using [Npgsql EntityFrameworkCore PostgreSQL](https://www.nuget.org/packages/Npgsql.EntityFrameworkCore.PostgreSQL) and bind it to the Syncfusion Angular Grid.
+
+PostgreSQL Server database can be bound to the Grid in different ways (i.e.) using [dataSource](https://ej2.syncfusion.com/angular/documentation/api/grid/#datasource) property, custom adaptor and remote data binding using various adaptors. In this documentation, two approaches will be examined to connect a PostgreSQL Server database to a Grid. Both the approaches have capability to handle data and CRUD operations with built-in methods as well as can be customized as per your own.
+
+**1. Using UrlAdaptor**
+
+The [UrlAdaptor](https://blazor.syncfusion.com/documentation/data/adaptors#url-adaptor) serves as the base adaptor for facilitating communication between remote data services and an UI component. It enables the remote binding of data to the Syncfusion Angular Grid by connecting to an existing pre-configured API service linked to the PostgreSQL Server database. While the Grid supports various adaptors to fulfill this requirement, including [Web API](https://ej2.syncfusion.com/angular/documentation/grid/connecting-to-adaptors/web-api-adaptor), [ODataV4](https://ej2.syncfusion.com/angular/documentation/grid/connecting-to-adaptors/odatav4-adaptor), [UrlAdaptor](https://blazor.syncfusion.com/documentation/data/adaptors#url-adaptor), and [GraphQL](https://ej2.syncfusion.com/angular/documentation/grid/connecting-to-adaptors/graphql-adaptor), the `UrlAdaptor` is particularly useful for the scenarios where a custom API service with unique logic for handling data and CRUD operations is in place. This approach allows for custom handling of data and CRUD operations, and the resultant data returned in the `result` and `count` format for display in the Grid.
+
+**2. Using CustomAdaptor**
+
+The [CustomAdaptor](https://ej2.syncfusion.com/angular/documentation/grid/connecting-to-adaptors/custom-adaptor) serves as a mediator between the UI component and the database for data binding. While the data source from the database can be directly bound to the Syncfusion Angular Grid locally using the `dataSource` property, the `CustomAdaptor` approach is preferred as it allows for customization of both data operations and CRUD operations according to specific requirements. In this approach, for every action in the Grid, a corresponding request with action details is sent to the `CustomAdaptor`. The Grid provides predefined methods to perform data operations such as **searching**, **filtering**, **sorting**, **aggregation**, **paging** and **grouping**. Alternatively, your own custom methods can be employed to execute operations and return the data in the `result` and `count` format for displaying in the Grid. Additionally, for CRUD operations, predefined methods can be overridden to provide custom functionality. Further details on this can be found in the latter part of the documentation.
+
+## Binding data from PostgreSQL Server using an API service
+
+This section describes step by step process how to retrieve data from a PostgreSQL Server using an API service and bind it to the Syncfusion Angular Grid.
+
+### Creating an API service
+
+**1.** Open Visual Studio and create an Angular and ASP.NET Core project named **Grid_PostgreSQL**. To create an Angular and ASP.NET Core application, follow the documentation [link](https://learn.microsoft.com/en-us/visualstudio/javascript/tutorial-asp-net-core-with-angular?view=vs-2022) for detailed steps.
+
+**2.** To connect a PostgreSQL Server database using the PostgreSQL driver in your application, you need to install the [Npgsql.EntityFrameworkCore.PostgreSQL ](https://www.nuget.org/packages/Npgsql.EntityFrameworkCore.PostgreSQL) NuGet package. To add **Npgsql.EntityFrameworkCore.PostgreSQL** in the app, open the NuGet package manager in Visual Studio (Tools → NuGet Package Manager → Manage NuGet Packages for Solution), search and install it.
+
+**3.** Create an API controller (aka, GridController.cs) file under **Controllers** folder that helps to establish data communication with the Syncfusion Angular Grid.
+
+**4.** In an API controller (aka, GridController), connect to PostgreSQL Server. In the **GetOrderData()** method **NpgsqlConnection** helps to connect the PostgreSQL Server database. Next, using **NpgsqlCommand** and **NpgsqlDataAdapter** you can process the desired Npgsql query string and retrieve data from the database. The **Fill** method of the **DataAdapter** is used to populate the Npgsql data into a **DataTable** as shown in the following code snippet.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+using Microsoft.AspNetCore.Mvc;
+using System.ComponentModel.DataAnnotations;
+using System.Data;
+using Syncfusion.EJ2.Base;
+using Npgsql;
+
+namespace Grid_PostgreSQL_Custom.Server.Controllers
+{
+ [ApiController]
+ public class GridController : ControllerBase
+ {
+
+ string ConnectionString = @"";
+
+ ///
+ /// Processes the DataManager request to perform searching, filtering, sorting, and paging operations.
+ ///
+ /// Contains the details of the data operation requested.
+ /// Returns a JSON object along with the total record count.
+ [HttpPost]
+ [Route("api/[controller]")]
+ public object Post([FromBody] DataManagerRequest DataManagerRequest)
+ {
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+ }
+
+ ///
+ /// Retrieves the order data from the database.
+ ///
+ /// Returns a list of orders fetched from the database.
+ [HttpGet]
+ [Route("api/[controller]")]
+ public List GetOrderData()
+ {
+ // Define the SQL query to retrieve all orders from the database, ordered by OrderID.
+ string queryStr = "SELECT * FROM public.\"Orders\" ORDER BY \"OrderID\"";
+
+ // Create a new NpgsqlConnection object using the connection string.
+ NpgsqlConnection Connection = new(ConnectionString);
+
+ // Open the database connection before executing the query.
+ Connection.Open();
+
+ //Using NpgsqlCommand and query create connection with database.
+ NpgsqlCommand Command = new(queryStr, Connection);
+
+ // Using NpgsqlDataAdapter to execute the NpgsqlCommand and fill the results into a DataTable.
+ NpgsqlDataAdapter DataAdapter = new(Command);
+
+ // Create a DataTable to hold the data retrieved from the database.
+ DataTable DataTable = new();
+
+ // Using NpgsqlDataAdapter, process the query string and fill the data into the dataset.
+ DataAdapter.Fill(DataTable);
+
+ // Close the connection after executing the command.
+ Connection.Close();
+
+ // Cast the data fetched from NpgsqlDataAdapter to List.
+ List dataSource = (from DataRow Data in DataTable.Rows
+ select new Orders()
+ {
+ OrderID = Convert.ToInt32(Data["OrderID"]),
+ CustomerID = Data["CustomerID"].ToString(),
+ EmployeeID = Convert.ToInt32(Data["EmployeeID"]),
+ ShipCity = Data["ShipCity"].ToString(),
+ Freight = Convert.ToDecimal(Data["Freight"])
+ }).ToList();
+ return dataSource;
+ }
+
+ public class Orders
+ {
+ [Key]
+ public int? OrderID { get; set; }
+ public string? CustomerID { get; set; }
+ public int? EmployeeID { get; set; }
+ public decimal Freight { get; set; }
+ public string? ShipCity { get; set; }
+ }
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**5.** Run the application and it will be hosted within the URL `https://localhost:xxxx`.
+
+**6.** Finally, the retrieved data from PostgreSQL Server database which is in the form of list can be found in an API controller available in the URL link `https://localhost:xxxx/api/Grid`, as shown in the browser page below.
+
+
+
+### Connecting Syncfusion Angular Grid to an API service
+
+To integrate the Syncfusion Angular Grid into your Angular and ASP.NET Core project using Visual Studio, follow the below steps:
+
+**Step 1: Install Syncfusion Package**
+
+Open your terminal in the project's client folder and install the required Syncfusion packages using npm:
+
+```bash
+npm install @syncfusion/ej2-angular-grids --save
+npm install @syncfusion/ej2-data --save
+```
+
+**Step 2: Import Grid Module**
+
+In the `app.module.ts` file, import the **GridModule** from the `@syncfusion/ej2-angular-grids` package:
+
+**Step 3: Adding CSS reference**
+
+Include the necessary CSS files in your `styles.css` file to style the Syncfusion Angular Grid:
+
+{% tabs %}
+{% highlight css tabtitle="styles.css" %}
+
+@import '../node_modules/@syncfusion/ej2-base/styles/material.css';
+@import '../node_modules/@syncfusion/ej2-buttons/styles/material.css';
+@import '../node_modules/@syncfusion/ej2-calendars/styles/material.css';
+@import '../node_modules/@syncfusion/ej2-dropdowns/styles/material.css';
+@import '../node_modules/@syncfusion/ej2-inputs/styles/material.css';
+@import '../node_modules/@syncfusion/ej2-navigations/styles/material.css';
+@import '../node_modules/@syncfusion/ej2-popups/styles/material.css';
+@import '../node_modules/@syncfusion/ej2-splitbuttons/styles/material.css';
+@import '../node_modules/@syncfusion/ej2-angular-grids/styles/material.css';
+
+{% endhighlight %}
+{% endtabs %}
+
+**2.** In your component file (e.g., app.component.ts), import `DataManager` and `UrlAdaptor` from `@syncfusion/ej2-data`. Create a [DataManager](https://ej2.syncfusion.com/angular/documentation/data/getting-started) instance specifying the URL of your API endpoint(https:localhost:xxxx/api/Grid) using the `url` property and set the adaptor `UrlAdaptor`.
+
+**3.** The `DataManager` offers multiple adaptor options to connect with remote database based on an API service. Below is an example of the `UrlAdaptor` configuration where an API service are set up to return the resulting data in the `result` and `count` format.
+
+**4.** The `UrlAdaptor` acts as the base adaptor for interacting with remote data service. Most of the built-in adaptors are derived from the `UrlAdaptor`.
+
+{% tabs %}
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
+import { GridComponent, GridModule } from '@syncfusion/ej2-angular-grids';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url:'https://localhost:xxxx/api/Grid', // Here xxxx represents the port number.
+ adaptor: new UrlAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+
+{% highlight cs tabtitle="GridController.cs" %}
+
+using Microsoft.AspNetCore.Mvc;
+using System.ComponentModel.DataAnnotations;
+using System.Data;
+using Syncfusion.EJ2.Base;
+using Npgsql;
+
+namespace Grid_PostgreSQL.Server.Controllers
+{
+ [ApiController]
+ public class GridController : ControllerBase
+ {
+
+ string ConnectionString = @"";
+
+ ///
+ /// Processes the DataManager request to perform searching, filtering, sorting, and paging operations.
+ ///
+ /// Contains the details of the data operation requested.
+ /// Returns a JSON object along with the total record count.
+ [HttpPost]
+ [Route("api/[controller]")]
+ public object Post([FromBody] DataManagerRequest DataManagerRequest)
+ {
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+ }
+
+ ///
+ /// Retrieves the order data from the database.
+ ///
+ /// Returns a list of orders fetched from the database.
+ [HttpGet]
+ [Route("api/[controller]")]
+ public List GetOrderData()
+ {
+ // Define the SQL query to retrieve all orders from the database, ordered by OrderID.
+ string queryStr = "SELECT * FROM public.\"Orders\" ORDER BY \"OrderID\"";
+
+ // Create a new NpgsqlConnection object using the connection string.
+ NpgsqlConnection Connection = new(ConnectionString);
+
+ // Open the database connection before executing the query.
+ Connection.Open();
+
+ //Using NpgsqlCommand and query create connection with database.
+ NpgsqlCommand Command = new(queryStr, Connection);
+
+ // Using NpgsqlDataAdapter to execute the NpgsqlCommand and fill the results into a DataTable.
+ NpgsqlDataAdapter DataAdapter = new(Command);
+
+ // Create a DataTable to hold the data retrieved from the database.
+ DataTable DataTable = new();
+
+ // Using NpgsqlDataAdapter, process the query string and fill the data into the dataset.
+ DataAdapter.Fill(DataTable);
+
+ // Close the connection after executing the command.
+ Connection.Close();
+
+ // Cast the data fetched from NpgsqlDataAdapter to List.
+ List dataSource = (from DataRow Data in DataTable.Rows
+ select new Orders()
+ {
+ OrderID = Convert.ToInt32(Data["OrderID"]),
+ CustomerID = Data["CustomerID"].ToString(),
+ EmployeeID = Convert.ToInt32(Data["EmployeeID"]),
+ ShipCity = Data["ShipCity"].ToString(),
+ Freight = Convert.ToDecimal(Data["Freight"])
+ }).ToList();
+ return dataSource;
+ }
+
+ public class Orders
+ {
+ [Key]
+ public int? OrderID { get; set; }
+ public string? CustomerID { get; set; }
+ public int? EmployeeID { get; set; }
+ public decimal Freight { get; set; }
+ public string? ShipCity { get; set; }
+ }
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+> Replace https://localhost:xxxx/api/Grid with the actual **URL** of your API endpoint that provides the data in a consumable format (e.g., JSON).
+
+**5.** Run the application in Visual Studio. It will be accessible via a URL like **https://localhost:xxxx**.
+
+> Ensure your API service is configured to handle CORS (Cross-Origin Resource Sharing) if necessary.
+ ```cs
+ [program.cs]
+ builder.Services.AddCors(options =>
+ {
+ options.AddDefaultPolicy(builder =>
+ {
+ builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
+ });
+ });
+ var app = builder.Build();
+ app.UseCors();
+ ```
+
+> * The Syncfusion Angular Grid provides built-in support for handling various data operations such as searching, sorting, filtering, aggregate and paging on the server-side. These operations can be handled using methods such as `PerformSearching`, `PerformFiltering`, `PerformSorting`, `PerformTake` and `PerformSkip` available in the [Syncfusion.EJ2.AspNet.Core](https://www.nuget.org/packages/Syncfusion.EJ2.AspNet.Core/) package. Let’s explore how to manage these data operations using the `UrlAdaptor`.
+> * In an API service project, add `Syncfusion.EJ2.AspNet.Core` by opening the NuGet package manager in Visual Studio (Tools → NuGet Package Manager → Manage NuGet Packages for Solution), search and install it.
+> * To access `DataManagerRequest` and `QueryableOperation`, import `Syncfusion.EJ2.Base` in `GridController.cs` file.
+
+### Handling searching operation
+
+To handle searching operation, ensure that your API endpoint supports custom searching criteria. Implement the searching logic on the server-side using the `PerformSearching` method from the `QueryableOperation` class. This allows the custom data source to undergo searching based on the criteria specified in the incoming `DataManagerRequest` object.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform searching operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the searched data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Handling searching operation.
+ if (DataManagerRequest.Search != null && DataManagerRequest.Search.Count > 0)
+ {
+ DataSource = queryableOperation.PerformSearching(DataSource, DataManagerRequest.Search);
+ //Add custom logic here if needed and remove above method.
+ }
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
+import { GridComponent, ToolbarItems, GridModule, ToolbarService } from '@syncfusion/ej2-angular-grids';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [ToolbarService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+ public toolbar?: ToolbarItems[];
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new UrlAdaptor()
+ });
+ this.toolbar = ['Search'];
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling filtering operation
+
+To handle filtering operation, ensure that your API endpoint supports custom filtering criteria. Implement the filtering logic on the server-side using the `PerformFiltering` method from the `QueryableOperation` class. This allows the custom data source to undergo filtering based on the criteria specified in the incoming `DataManagerRequest` object.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform filtering operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the filtered data along with the total record count.
+
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Handling filtering operation.
+ if (DataManagerRequest.Where != null && DataManagerRequest.Where.Count > 0)
+ {
+ foreach (WhereFilter condition in DataManagerRequest.Where)
+ {
+ foreach (WhereFilter predicate in condition.predicates)
+ {
+ DataSource = queryableOperation.PerformFiltering(DataSource, DataManagerRequest.Where, predicate.Operator);
+ //Add custom logic here if needed and remove above method.
+ }
+ }
+ }
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
+import { GridComponent, FilterService, GridModule } from '@syncfusion/ej2-angular-grids';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [FilterService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid')public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new UrlAdaptor()
+ });
+ }
+}
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling sorting operation
+
+To handle sorting operation, ensure that your API endpoint supports custom sorting criteria. Implement the sorting logic on the server-side using the `PerformSorting` method from the `QueryableOperation` class. This allows the custom data source to undergo sorting based on the criteria specified in the incoming `DataManagerRequest` object.
+
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform sorting operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the sorted data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Handling sorting operation.
+ if (DataManagerRequest.Sorted != null && DataManagerRequest.Sorted.Count > 0)
+ {
+ DataSource = queryableOperation.PerformSorting(DataSource, DataManagerRequest.Sorted);
+ //Add custom logic here if needed and remove above method.
+ }
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
+import { GridComponent, SortService, GridModule } from '@syncfusion/ej2-angular-grids';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [SortService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new UrlAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling paging operation
+
+To handle paging operation, ensure that your API endpoint supports custom paging criteria. Implement the paging logic on the server-side using the `PerformTake` and `PerformSkip`method from the `QueryableOperation` class. This allows the custom data source to undergo paging based on the criteria specified in the incoming `DataManagerRequest` object.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform paging operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the paginated data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Handling paging operation.
+ if (DataManagerRequest.Skip != 0)
+ {
+ DataSource = queryableOperation.PerformSkip(DataSource, DataManagerRequest.Skip);
+ //Add custom logic here if needed and remove above method.
+ }
+ if (DataManagerRequest.Take != 0)
+ {
+ DataSource = queryableOperation.PerformTake(DataSource, DataManagerRequest.Take);
+ //Add custom logic here if needed and remove above method.
+ }
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
+import { GridComponent, PageService, GridModule } from '@syncfusion/ej2-angular-grids';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [PageService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new UrlAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling CRUD operations
+
+The Syncfusion Angular Grid seamlessly integrates CRUD (Create, Read, Update, and Delete) operations with server-side controller actions through specific properties: `insertUrl`, `removeUrl`, `updateUrl` and `batchUrl`. These properties enable the Grid to communicate with the data service for every Grid action, facilitating server-side operations.
+
+**CRUD Operations Mapping**
+
+CRUD operations within the Grid can be mapped to server-side controller actions using specific properties:
+
+1. **insertUrl**: Specifies the URL for inserting new data.
+2. **removeUrl**: Specifies the URL for removing existing data.
+3. **updateUrl**: Specifies the URL for updating existing data.
+4. **batchUrl**: Specifies the URL for batch editing.
+
+To enable editing in Grid, refer to the editing [documentation](https://ej2.syncfusion.com/angular/documentation/grid/editing/edit). In the below example, the inline edit [mode](https://ej2.syncfusion.com/angular/documentation/api/grid/editSettings/#mode) is enabled and [toolbar](https://helpej2.syncfusion.com/angular/documentation/api/grid/#toolbar) property is configured to display toolbar items for editing purposes.
+
+{% tabs %}
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
+import { GridComponent, EditSettingsModel, GridModule, ToolbarItems,EditService, ToolbarService } from '@syncfusion/ej2-angular-grids';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [EditService, ToolbarService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+ public editSettings?: EditSettingsModel;
+ public toolbar?: ToolbarItems[];
+ public employeeIDRules?: Object;
+ public customerIDRules?: Object;
+ public freightRules?: Object;
+ public shipCityRules?: Object;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ insertUrl: 'https://localhost:xxxx/api/Grid/Insert',
+ updateUrl: 'https://localhost:xxxx/api/Grid/Update',
+ removeUrl: 'https://localhost:xxxx/api/Grid/Remove',
+ // Enable batch URL when batch editing is enabled.
+ //batchUrl: 'https://localhost:xxxx/api/Grid/BatchUpdate',
+ adaptor: new UrlAdaptor()
+ });
+ this.employeeIDRules = { required: true, number: true };
+ this.customerIDRules = { required: true };
+ this.freightRules = { required: true, min: 1, max: 1000 };
+ this.shipCityRules = { required: true };
+ this.toolbar = ['Add', 'Update', 'Delete', 'Cancel', 'Search'];
+ this.editSettings = { allowAdding: true, allowDeleting: true, allowEditing: true, mode: 'Normal' };
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+{% endtabs %}
+
+> * Normal/Inline editing is the default edit [mode](https://ej2.syncfusion.com/angular/documentation/api/grid/editSettings/#mode) for the Grid. To enable CRUD operations, ensure that the [isPrimaryKey](https://ej2.syncfusion.com/angular/documentation/api/grid/column/#isprimarykey) property is set to **true** for a specific Grid column, ensuring that its value is unique.
+> * If database has an auto generated column, ensure to define [isIdentity](https://ej2.syncfusion.com/angular/documentation/api/grid/column/#isidentity) property of Grid column to disable them during adding or editing operations.
+
+**Insert Operation:**
+
+To insert a new row, simply click the **Add** toolbar button. The new record edit form will be displayed as shown below. Upon clicking the **Update** toolbar button, the record will be inserted into the **Orders** table by calling the following **POST** method of an API.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Inserts a new data item into the data collection.
+///
+/// It contains the new record detail which is need to be inserted.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/Insert")]
+public void Insert([FromBody] CRUDModel value)
+{
+ // Create query to insert the specific into the database by accessing its properties.
+ string queryStr = $"Insert into \"Orders\" (\"CustomerID\", \"Freight\", \"ShipCity\", \"EmployeeID\") values('{value.value.CustomerID}',{value.value.Freight},'{value.value.ShipCity}','{value.value.EmployeeID}')";
+
+ // Create a new NpgsqlConnection object using the connection string.
+ NpgsqlConnection Connection = new NpgsqlConnection(ConnectionString);
+
+ // Open the database connection before executing the query.
+ Connection.Open();
+
+ // Execute the Npgsql command.
+ NpgsqlCommand Command = new NpgsqlCommand(queryStr, Connection);
+
+ // Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the command.
+ Connection.Close();
+
+ // Add custom logic here if needed and remove the above method.
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**Update Operation:**
+
+To edit a row, first select desired row and click the **Edit** toolbar button. The edit form will be displayed and proceed to modify any column value as per your requirement. Clicking the **Update** toolbar button will update the edit record in the **Orders** table by involving the following **Post** method of an API.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Update a existing data item from the data collection.
+///
+/// It contains the updated record detail which is need to be updated.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/Update")]
+public void Update([FromBody] CRUDModel value)
+{
+ // Create query to update the changes into the database by accessing its properties.
+ string queryStr = $"Update \"Orders\" set \"CustomerID\"='{value.value.CustomerID}', \"Freight\"={value.value.Freight},\"EmployeeID\"={value.value.EmployeeID},\"ShipCity\"='{value.value.ShipCity}' where \"OrderID\"={value.value.OrderID}";
+
+ // Create a new NpgsqlConnection object using the connection string.
+ NpgsqlConnection Connection = new NpgsqlConnection(ConnectionString);
+
+ // Open the database connection before executing the query.
+ Connection.Open();
+
+ // Execute the Npgsql command.
+ NpgsqlCommand Command = new NpgsqlCommand(queryStr, Connection);
+
+ // Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the command.
+ Connection.Close();
+
+ // Add custom logic here if needed and remove the above method.
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**Delete Operation:**
+
+To delete a row, simply select the desired row and click the **Delete** toolbar button. This action will trigger a **DELETE** request to an API, containing the primary key value of the selected record. As a result corresponding record will be removed from the **Orders** table.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Remove a specific data item from the data collection.
+///
+/// It contains the specific record detail which is need to be removed.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/Remove")]
+public void Remove([FromBody] CRUDModel value)
+{
+ //Create query to remove the specific from database by passing the primary key column value.
+ string queryStr = $"DELETE FROM \"Orders\" WHERE \"OrderID\" = {value.key}";
+
+ // Create a new NpgsqlConnection object using the connection string.
+ NpgsqlConnection Connection = new NpgsqlConnection(ConnectionString);
+
+ // Open the database connection before executing the query.
+ Connection.Open();
+
+ // Execute the Npgsql command.
+ NpgsqlCommand Command = new NpgsqlCommand(queryStr, Connection);
+
+ //Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the command.
+ Connection.Close();
+
+ //Add custom logic here if needed and remove above method.
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**Batch Operation:**
+
+To perform batch operation, define the edit [mode](https://ej2.syncfusion.com/angular/documentation/api/grid/editSettings/#mode) as **Batch** and specify the `batchUrl` property in the `DataManager`. Use the **Add** toolbar button to insert new row in batch editing mode. To edit a cell, double-click the desired cell and update the value as required. To delete a record, simply select the record and press the **Delete** toolbar button. Now, all CRUD operations will be executed in batch editing mode. Clicking the **Update** toolbar button will update the newly added, edited, or deleted records from the **Orders** table using a single API **POST** request.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Batch update (Insert, Update, and Delete) a collection of data items from the data collection.
+///
+/// The set of information along with details about the CRUD actions to be executed from the database.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/BatchUpdate")]
+public IActionResult BatchUpdate([FromBody] CRUDModel value)
+{
+ if (value.changed != null && value.changed.Count > 0)
+ {
+ foreach (Orders Record in (IEnumerable)value.changed)
+ {
+ // Create query to update the changes into the database by accessing its properties.
+ string queryStr = $"Update \"Orders\" set \"CustomerID\"='{Record.CustomerID}', \"Freight\"={Record.Freight},\"EmployeeID\"={Record.EmployeeID},\"ShipCity\"='{Record.ShipCity}' where \"OrderID\"={Record.OrderID}";
+
+ // Create a new NpgsqlConnection object using the connection string.
+ NpgsqlConnection Connection = new NpgsqlConnection(ConnectionString);
+
+ // Open the database connection before executing the query.
+ Connection.Open();
+
+ // Execute the Npgsql command.
+ NpgsqlCommand Command = new NpgsqlCommand(queryStr, Connection);
+
+ // Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the command.
+ Connection.Close();
+
+ // Add custom logic here if needed and remove the above method.
+ }
+ }
+ if (value.added != null && value.added.Count > 0)
+ {
+ foreach (Orders Record in (IEnumerable)value.added)
+ {
+ // Create query to insert the specific into the database by accessing its properties.
+ string queryStr = $"Insert into \"Orders\" (\"CustomerID\", \"Freight\", \"ShipCity\", \"EmployeeID\") values('{Record.CustomerID}',{Record.Freight},'{Record.ShipCity}','{Record.EmployeeID}')";
+
+ // Create a new NpgsqlConnection object using the connection string.
+ NpgsqlConnection Connection = new NpgsqlConnection(ConnectionString);
+
+ // Open the database connection before executing the query.
+ Connection.Open();
+
+ // Execute the Npgsql command.
+ NpgsqlCommand Command = new NpgsqlCommand(queryStr, Connection);
+
+ // Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the command.
+ Connection.Close();
+
+ // Add custom logic here if needed and remove the above method.
+ }
+ }
+ if (value.deleted != null && value.deleted.Count > 0)
+ {
+ foreach (Orders Record in (IEnumerable)value.deleted)
+ {
+ //Create query to remove the specific from database by passing the primary key column value.
+ string queryStr = $"DELETE FROM \"Orders\" WHERE \"OrderID\" = {Record.OrderID}";
+
+ // Create a new NpgsqlConnection object using the connection string.
+ NpgsqlConnection Connection = new NpgsqlConnection(ConnectionString);
+
+ // Open the database connection before executing the query.
+ Connection.Open();
+
+ // Execute the Npgsql command.
+ NpgsqlCommand Command = new NpgsqlCommand(queryStr, Connection);
+
+ //Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the command.
+ Connection.Close();
+
+ //Add custom logic here if needed and remove above method.
+ }
+ }
+ return new JsonResult(value);
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+When you run the application, the resultant Syncfusion Angular Grid will look like this
+
+
+
+> Please find the sample in this [GitHub location](https://github.com/SyncfusionExamples/connecting-databases-to-angular-grid/tree/master/Binding%20PostgreSQL%20database%20using%20UrlAdaptor/Grid_PostgreSQL).
+
+## Binding data from PostgreSQL Server using CustomAdaptor
+
+This section describes step by step process how to retrieve data from a PostgreSQL Server using `CustomAdaptor` and bind it to the Grid.
+
+**1.** To create a simple Grid, the procedure is explained in the above-mentioned topic on [Connecting Syncfusion Angular Grid to an API service](#connecting-syncfusion-angular-grid-to-an-api-service)
+
+**2.** To connect a PostgreSQL Server database using the PostgreSQL driver in your application, you need to install the [Npgsql.EntityFrameworkCore.PostgreSQL](https://www.nuget.org/packages/Npgsql.EntityFrameworkCore.PostgreSQL) NuGet package. To add **Npgsql.EntityFrameworkCore.PostgreSQL** in the app, open the NuGet package manager in Visual Studio (Tools → NuGet Package Manager → Manage NuGet Packages for Solution), search and install it.
+
+**3.** If you intend to inject your own service into the `CustomAdaptor` and utilize it, you can achieve this as follows:
+
+ * Create a `CustomAdaptor` that extends the `UrlAdaptor` class.
+ * Override the `processResponse` method to process server responses.
+
+**4.** Within the `processResponse` method of `CustomAdaptor`, fetch data by calling the **GetOrderData** method.
+
+ * In this `GetOrderData` method, the PostgreSQL Server database data is fetch by using the **NpgsqlDataAdapter** class.
+
+ * Employ the **Fill** method of the **DataAdapter** to populate a **DataSet** with the results of the `Select` command of the **DataAdapter**, followed by conversion of the **DataSet** into a List.
+
+ * Finally, return the response as a `result` and `count` pair object in the `processResponse` method to bind the data to the Grid.
+
+{% tabs %}
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager } from '@syncfusion/ej2-data';
+import { GridComponent, GridModule } from '@syncfusion/ej2-angular-grids';
+import { CustomAdaptor } from './CustomAdaptor'
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid',
+ adaptor: new CustomAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="CustomAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+}
+
+{% endhighlight %}
+
+{% highlight cs tabtitle="GridController.cs" %}
+
+using Microsoft.AspNetCore.Mvc;
+using System.ComponentModel.DataAnnotations;
+using System.Data;
+using Syncfusion.EJ2.Base;
+using Npgsql;
+
+namespace Grid_PostgreSQL.Server.Controllers
+{
+ [ApiController]
+ public class GridController : ControllerBase
+ {
+
+ string ConnectionString = @"";
+
+ ///
+ /// Processes the DataManager request to perform searching, filtering, sorting, and paging operations.
+ ///
+ /// Contains the details of the data operation requested.
+ /// Returns a JSON object along with the total record count.
+ [HttpPost]
+ [Route("api/[controller]")]
+ public object Post([FromBody] DataManagerRequest DataManagerRequest)
+ {
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+ }
+
+ ///
+ /// Retrieves the order data from the database.
+ ///
+ /// Returns a list of orders fetched from the database.
+ [HttpGet]
+ [Route("api/[controller]")]
+ public List GetOrderData()
+ {
+ // Define the SQL query to retrieve all orders from the database, ordered by OrderID.
+ string queryStr = "SELECT * FROM public.\"Orders\" ORDER BY \"OrderID\"";
+
+ // Create a new NpgsqlConnection object using the connection string.
+ NpgsqlConnection Connection = new(ConnectionString);
+
+ // Open the database connection before executing the query.
+ Connection.Open();
+
+ //Using NpgsqlCommand and query create connection with database.
+ NpgsqlCommand Command = new(queryStr, Connection);
+
+ // Using NpgsqlDataAdapter to execute the NpgsqlCommand and fill the results into a DataTable.
+ NpgsqlDataAdapter DataAdapter = new(Command);
+
+ // Create a DataTable to hold the data retrieved from the database.
+ DataTable DataTable = new();
+
+ // Using NpgsqlDataAdapter, process the query string and fill the data into the dataset.
+ DataAdapter.Fill(DataTable);
+
+ // Close the connection after executing the command.
+ Connection.Close();
+
+ // Cast the data fetched from NpgsqlDataAdapter to List.
+ List dataSource = (from DataRow Data in DataTable.Rows
+ select new Orders()
+ {
+ OrderID = Convert.ToInt32(Data["OrderID"]),
+ CustomerID = Data["CustomerID"].ToString(),
+ EmployeeID = Convert.ToInt32(Data["EmployeeID"]),
+ ShipCity = Data["ShipCity"].ToString(),
+ Freight = Convert.ToDecimal(Data["Freight"])
+ }).ToList();
+ return dataSource;
+ }
+
+ public class Orders
+ {
+ [Key]
+ public int? OrderID { get; set; }
+ public string? CustomerID { get; set; }
+ public int? EmployeeID { get; set; }
+ public decimal Freight { get; set; }
+ public string? ShipCity { get; set; }
+ }
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+> * The `DataManagerRequest` encompasses details about the Grid actions such as searching, filtering, sorting, aggregate, paging and grouping.
+
+### Handling searching operation
+
+When utilizing the `CustomAdaptor` in Angular, managing the searching operation involves overriding the `processResponse` method of the `UrlAdaptor` class.
+
+In the code example below, searching a custom data source can be accomplished by employing the built-in `PerformSearching` method of the `QueryableOperation` class. Alternatively, you can implement your own method for searching operation and bind the resultant data to the Grid.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform searching operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the searched data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Handling searching operation.
+ if (DataManagerRequest.Search != null && DataManagerRequest.Search.Count > 0)
+ {
+ DataSource = queryableOperation.PerformSearching(DataSource, DataManagerRequest.Search);
+ //Add custom logic here if needed and remove above method.
+ }
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager } from '@syncfusion/ej2-data';
+import { GridComponent, ToolbarItems, ToolbarService, GridModule} from '@syncfusion/ej2-angular-grids';
+import { CustomAdaptor } from './CustomAdaptor'
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [ToolbarService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+ public toolbar?: ToolbarItems[];
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new CustomAdaptor()
+ });
+ this.toolbar = ['Search'];
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+
+
+{% highlight ts tabtitle="customAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling filtering operation
+
+When utilizing the `CustomAdaptor` in Angular, managing the filtering operation involves overriding the `processResponse` method of the `UrlAdaptor` class.
+
+In the code example below, filtering a custom data source can be achieved by utilizing the built-in `PerformFiltering` method of the `QueryableOperation` class. Alternatively, you can implement your own method for filtering operation and bind the resulting data to the Grid.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform filtering operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the filtered data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Handling filtering operation.
+ if (DataManagerRequest.Where != null && DataManagerRequest.Where.Count > 0)
+ {
+ foreach (WhereFilter condition in DataManagerRequest.Where)
+ {
+ foreach (WhereFilter predicate in condition.predicates)
+ {
+ DataSource = queryableOperation.PerformFiltering(DataSource, DataManagerRequest.Where, predicate.Operator);
+ //Add custom logic here if needed and remove above method.
+ }
+ }
+ }
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager } from '@syncfusion/ej2-data';
+import { GridComponent, FilterService, GridModule } from '@syncfusion/ej2-angular-grids';
+import { CustomAdaptor } from './CustomAdaptor'
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [FilterService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid')public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new CustomAdaptor()
+ });
+ }
+}
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="customAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling sorting operation
+
+When utilizing the `CustomAdaptor` in Angular, managing the sorting operation involves overriding the `processResponse` method of the `UrlAdaptor` class.
+
+In the code example below, sorting a custom data source can be accomplished by employing the built-in `PerformSorting` method of the `QueryableOperation` class. Alternatively, you can implement your own method for sorting operation and bind the resulting data to the Grid.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform sorting operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the sorted data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Handling sorting operation.
+ if (DataManagerRequest.Sorted != null && DataManagerRequest.Sorted.Count > 0)
+ {
+ DataSource = queryableOperation.PerformSorting(DataSource, DataManagerRequest.Sorted);
+ //Add custom logic here if needed and remove above method.
+ }
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager } from '@syncfusion/ej2-data';
+import { GridComponent, SortService, GridModule } from '@syncfusion/ej2-angular-grids';
+import { CustomAdaptor } from './CustomAdaptor'
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [SortService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new CustomAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="customAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling paging operation
+
+When utilizing the `CustomAdaptor` in Angular, managing the paging operation involves overriding the `processResponse` method of the `UrlAdaptor` class.
+
+In the code example below, paging a custom data source can be achieved by utilizing the built-in `PerformTake` and `PerformSkip` method of the `QueryableOperation` class. Alternatively, you can use your own method for paging operation and bind the resulting data to the Grid.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform paging operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the paginated data along with the total record count.
+ [HttpPost]
+ [Route("api/[controller]")]
+ public object Post([FromBody] DataManagerRequest DataManagerRequest)
+ {
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Handling paging operation.
+ if (DataManagerRequest.Skip != 0)
+ {
+ DataSource = queryableOperation.PerformSkip(DataSource, DataManagerRequest.Skip);
+ //Add custom logic here if needed and remove above method.
+ }
+ if (DataManagerRequest.Take != 0)
+ {
+ DataSource = queryableOperation.PerformTake(DataSource, DataManagerRequest.Take);
+ //Add custom logic here if needed and remove above method.
+ }
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+ }
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager } from '@syncfusion/ej2-data';
+import { GridComponent, PageService, GridModule } from '@syncfusion/ej2-angular-grids';
+import { CustomAdaptor } from './CustomAdaptor'
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [PageService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new CustomAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="customAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling CRUD operations
+
+To enable editing in the Syncfusion Angular Grid, utilize the [editSettings](https://ej2.syncfusion.com/angular/documentation/api/grid/editSettings/) property. The Grid offers multiple edit modes including the **Inline/Normal**, **Dialog** and **Batch** editing. For more details, refer to the Grid [editing](https://ej2.syncfusion.com/angular/documentation/grid/editing/edit) documentation.
+
+In this scenario, the inline edit [mode](https://ej2.syncfusion.com/angular/documentation/api/grid/editSettings/#mode) and [toolbar](https://ej2.syncfusion.com/angular/documentation/api/grid/#toolbar) property configured to display toolbar items for editing purpose.
+
+{% tabs %}
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager } from '@syncfusion/ej2-data';
+import { GridComponent, EditSettingsModel, ToolbarItems, EditService, GridModule } from '@syncfusion/ej2-angular-grids';
+import { CustomAdaptor } from './CustomAdaptor'
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [EditService, ToolbarService ],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+ public editSettings?: EditSettingsModel;
+ public toolbar?: ToolbarItems[];
+ public employeeIDRules?: Object;
+ public customerIDRules?: Object;
+ public freightRules?: Object;
+ public shipCityRules?: Object;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid',
+ insertUrl: 'https://localhost:xxxx/api/Grid/Insert',
+ updateUrl: 'https://localhost:xxxx/api/Grid/Update',
+ removeUrl: 'https://localhost:xxxx/api/Grid/Remove',
+ // Enable batch URL when batch editing is enabled.
+ //batchUrl: 'https://localhost:xxxx/api/Grid/BatchUpdate',
+ adaptor: new CustomAdaptor()
+ });
+ this.employeeIDRules = { required: true, number: true };
+ this.customerIDRules = { required: true };
+ this.freightRules = { required: true, min: 1, max: 1000 };
+ this.shipCityRules = { required: true };
+ this.toolbar = ['Add', 'Update', 'Delete', 'Cancel', 'Search'];
+ this.editSettings = { allowAdding: true, allowDeleting: true, allowEditing: true, mode: 'Normal' };
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+{% endtabs %}
+
+> * Normal/Inline editing is the default edit `mode` for the Grid. To enable CRUD operations, ensure that the [isPrimaryKey](https://ej2.syncfusion.com/angular/documentation/api/grid/column/#isprimarykey) property is set to **true** for a specific Grid column, ensuring that its value is unique.
+> * If database has an auto generated column, ensure to define [isIdentity](https://ej2.syncfusion.com/angular/documentation/api/grid/column/#isidentity) property of Grid column to disable them during adding or editing operations.
+
+The CRUD operations can be performed and customized on our own by overriding the following CRUD methods of the `UrlAdaptor`
+
+* insert
+* remove
+* update
+* batchRequest
+
+Let’s see how to perform CRUD operation using PostgreSQL Server data with Grid.
+
+**Insert Operation:**
+
+To execute the insert operation, you will need to override the `insert` method of the `CustomAdaptor`. Then, integrate the following code snippet into the `CustomAdaptor` class. The below code snippet demonstrated how to handle the insertion of new records within the `insert` method of `CustomAdaptor`. Modify the logic within this method according to the requirements of your application.
+
+{% tabs %}
+{% highlight ts tabtitle="CustomAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+
+ public override insert(dm: any, data: any): any {
+ return {
+ url: dm.dataSource.insertUrl || dm.dataSource.url,
+ data: JSON.stringify({
+ __RequestVerificationToken: "Syncfusion",
+ value: data,
+ action: 'insert'
+ }),
+ type: 'POST'
+ };
+ }
+}
+
+{% endhighlight %}
+
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Inserts a new data item into the data collection.
+///
+/// It contains the new record detail which is need to be inserted.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/Insert")]
+public void Insert([FromBody] CRUDModel value)
+{
+ // Create query to insert the specific into the database by accessing its properties.
+ string queryStr = $"Insert into \"Orders\" (\"CustomerID\", \"Freight\", \"ShipCity\", \"EmployeeID\") values('{value.value.CustomerID}',{value.value.Freight},'{value.value.ShipCity}','{value.value.EmployeeID}')";
+
+ // Create a new NpgsqlConnection object using the connection string.
+ NpgsqlConnection Connection = new NpgsqlConnection(ConnectionString);
+
+ // Open the database connection before executing the query.
+ Connection.Open();
+
+ // Execute the Npgsql command.
+ NpgsqlCommand Command = new NpgsqlCommand(queryStr, Connection);
+
+ // Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the command.
+ Connection.Close();
+
+ // Add custom logic here if needed and remove the above method.
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**Update Operation:**
+
+To execute the update operation, override the `update` method of the `CustomAdaptor`. Then, integrate the following code snippet into the `CustomAdaptor` class. The below code snippet demonstrated how to handle the updating of existing records within the `update` method of the `CustomAdaptor`. Modify the logic within this method according to the requirements of your application.
+
+{% tabs %}
+{% highlight ts tabtitle="CustomAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+
+ public override update(dm: any, keyField: string, value: any): any {
+ return {
+ url: dm.dataSource.updateUrl || dm.dataSource.url,
+ data: JSON.stringify({
+ __RequestVerificationToken: "Syncfusion",
+ value: value,
+ action: 'update'
+ }),
+ type: 'POST'
+ };
+ }
+}
+
+{% endhighlight %}
+
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Update a existing data item from the data collection.
+///
+/// It contains the updated record detail which is need to be updated.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/Update")]
+public void Update([FromBody] CRUDModel value)
+{
+ // Create query to update the changes into the database by accessing its properties.
+ string queryStr = $"Update \"Orders\" set \"CustomerID\"='{value.value.CustomerID}', \"Freight\"={value.value.Freight},\"EmployeeID\"={value.value.EmployeeID},\"ShipCity\"='{value.value.ShipCity}' where \"OrderID\"={value.value.OrderID}";
+
+ // Create a new NpgsqlConnection object using the connection string.
+ NpgsqlConnection Connection = new NpgsqlConnection(ConnectionString);
+
+ // Open the database connection before executing the query.
+ Connection.Open();
+
+ // Execute the Npgsql command.
+ NpgsqlCommand Command = new NpgsqlCommand(queryStr, Connection);
+
+ // Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the command.
+ Connection.Close();
+
+ // Add custom logic here if needed and remove the above method.
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**Delete Operation:**
+
+To perform the delete operation, you need to override the `remove` method of the `CustomAdaptor`. Below is the code snippet that you can add to `CustomAdaptor` class. The below code snippet demonstrated how to handle the deletion of existing records within the `remove` method of `CustomAdaptor`. Modify the logic within this method according to the requirements of your application.
+
+{% tabs %}
+{% highlight ts tabtitle="CustomAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+
+ public override remove(dm: any, keyField: string, value: any): any {
+ return {
+ url: dm.dataSource.removeUrl || dm.dataSource.url,
+ data: JSON.stringify({
+ __RequestVerificationToken: "Syncfusion",
+ key: value,
+ keyColumn: keyField,
+ action: 'remove'
+ }),
+ type: 'POST'
+ };
+ }
+}
+
+{% endhighlight %}
+
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Remove a specific data item from the data collection.
+///
+/// It contains the specific record detail which is need to be removed.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/Remove")]
+public void Remove([FromBody] CRUDModel value)
+{
+ //Create query to remove the specific from database by passing the primary key column value.
+ string queryStr = $"DELETE FROM \"Orders\" WHERE \"OrderID\" = {value.key}";
+
+ // Create a new NpgsqlConnection object using the connection string.
+ NpgsqlConnection Connection = new NpgsqlConnection(ConnectionString);
+
+ // Open the database connection before executing the query.
+ Connection.Open();
+
+ // Execute the Npgsql command.
+ NpgsqlCommand Command = new NpgsqlCommand(queryStr, Connection);
+
+ //Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the command.
+ Connection.Close();
+
+ //Add custom logic here if needed and remove above method.
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**Batch Operation:**
+
+To perform the batch operation, override the **batchRequest** method of the `CustomAdaptor` and add the following code in the `CustomAdaptor`. The below code snippet demonstrated how to handle the batch update request within the **batchRequest** method of `CustomAdaptor`. Modify the logic within this method according to the requirements of your application.
+
+{% tabs %}
+{% highlight ts tabtitle="CustomAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+
+ public override batchRequest(dm:any, changes: any, e:any, query: any, original?: Object): Object {
+ return {
+ url: dm.dataSource.batchUrl || dm.dataSource.url,
+ data: JSON.stringify({
+ __RequestVerificationToken: "Syncfusion",
+ added: changes.addedRecords,
+ changed: changes.changedRecords,
+ deleted: changes.deletedRecords,
+ key: e.key,
+ action: 'batch'
+ }),
+ type: 'POST'
+ };
+ }
+}
+
+{% endhighlight %}
+
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Batch update (Insert, Update, and Delete) a collection of data items from the data collection.
+///
+/// The set of information along with details about the CRUD actions to be executed from the database.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/BatchUpdate")]
+public IActionResult BatchUpdate([FromBody] CRUDModel value)
+{
+ if (value.changed != null && value.changed.Count > 0)
+ {
+ foreach (Orders Record in (IEnumerable)value.changed)
+ {
+ // Create query to update the changes into the database by accessing its properties.
+ string queryStr = $"Update \"Orders\" set \"CustomerID\"='{Record.CustomerID}', \"Freight\"={Record.Freight},\"EmployeeID\"={Record.EmployeeID},\"ShipCity\"='{Record.ShipCity}' where \"OrderID\"={Record.OrderID}";
+
+ // Create a new NpgsqlConnection object using the connection string.
+ NpgsqlConnection Connection = new NpgsqlConnection(ConnectionString);
+
+ // Open the database connection before executing the query.
+ Connection.Open();
+
+ // Execute the Npgsql command.
+ NpgsqlCommand Command = new NpgsqlCommand(queryStr, Connection);
+
+ // Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the command.
+ Connection.Close();
+
+ // Add custom logic here if needed and remove the above method.
+ }
+ }
+ if (value.added != null && value.added.Count > 0)
+ {
+ foreach (Orders Record in (IEnumerable)value.added)
+ {
+ // Create query to insert the specific into the database by accessing its properties.
+ string queryStr = $"Insert into \"Orders\" (\"CustomerID\", \"Freight\", \"ShipCity\", \"EmployeeID\") values('{Record.CustomerID}',{Record.Freight},'{Record.ShipCity}','{Record.EmployeeID}')";
+
+ // Create a new NpgsqlConnection object using the connection string.
+ NpgsqlConnection Connection = new NpgsqlConnection(ConnectionString);
+
+ // Open the database connection before executing the query.
+ Connection.Open();
+
+ // Execute the Npgsql command.
+ NpgsqlCommand Command = new NpgsqlCommand(queryStr, Connection);
+
+ // Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the command.
+ Connection.Close();
+
+ // Add custom logic here if needed and remove the above method.
+ }
+ }
+ if (value.deleted != null && value.deleted.Count > 0)
+ {
+ foreach (Orders Record in (IEnumerable)value.deleted)
+ {
+ //Create query to remove the specific from database by passing the primary key column value.
+ string queryStr = $"DELETE FROM \"Orders\" WHERE \"OrderID\" = {Record.OrderID}";
+
+ // Create a new NpgsqlConnection object using the connection string.
+ NpgsqlConnection Connection = new NpgsqlConnection(ConnectionString);
+
+ // Open the database connection before executing the query.
+ Connection.Open();
+
+ // Execute the Npgsql command.
+ NpgsqlCommand Command = new NpgsqlCommand(queryStr, Connection);
+
+ //Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the command.
+ Connection.Close();
+
+ //Add custom logic here if needed and remove above method.
+ }
+ }
+ return new JsonResult(value);
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+
+
+> Please find the sample in this [GitHub location](https://github.com/SyncfusionExamples/connecting-databases-to-angular-grid/tree/master/Binding%20PostgreSQL%20database%20using%20CustomAdaptor).
\ No newline at end of file
diff --git a/ej2-angular/grid/connecting-to-database/sqlite-server.md b/ej2-angular/grid/connecting-to-database/sqlite-server.md
new file mode 100644
index 0000000000..954d536c6b
--- /dev/null
+++ b/ej2-angular/grid/connecting-to-database/sqlite-server.md
@@ -0,0 +1,2039 @@
+---
+layout: post
+title: Bind SQLite Server Data in Syncfusion Angular Grid
+description: Learn how to consume data from SQLite Server, bind it to Syncfusion Angular Grid, and perform CRUD operations.
+platform: ej2-angular
+control: grid
+keywords: adaptors, customadaptor, urladaptor, sqlite, remotedata
+documentation: ug
+domainurl: ##DomainURL##
+---
+
+# Connecting SQLite Server data to Syncfusion Angular Grid
+
+This section describes how to connect and retrieve data from a SQLite Server database using [Microsoft.Data.Sqlite](https://www.nuget.org/packages/Microsoft.Data.Sqlite/) and bind it to the Syncfusion Angular Grid.
+
+SQLite Server database can be bound to the Grid in different ways (i.e.) using [dataSource](https://ej2.syncfusion.com/angular/documentation/api/grid/#datasource) property, custom adaptor and remote data binding using various adaptors. In this documentation, two approaches will be examined to connect a SQLite Server database to a Grid. Both the approaches have capability to handle data and CRUD operations with built-in methods as well as can be customized as per your own.
+
+* **Using UrlAdaptor**
+
+The [UrlAdaptor](https://ej2.syncfusion.com/angular/documentation/grid/connecting-to-adaptors/url-adaptor?cs-save-lang=1&cs-lang=csharp) serves as the base adaptor for facilitating communication between remote data services and an UI component. It enables the remote binding of data to the Syncfusion Angular Grid by connecting to an existing pre-configured API service linked to the SQLite Server database. While the Grid supports various adaptors to fulfill this requirement, including [Web API](https://ej2.syncfusion.com/angular/documentation/grid/connecting-to-adaptors/web-api-adaptor), [ODataV4](https://ej2.syncfusion.com/angular/documentation/grid/connecting-to-adaptors/odatav4-adaptor), [UrlAdaptor](https://ej2.syncfusion.com/angular/documentation/grid/connecting-to-adaptors/url-adaptor?cs-save-lang=1&cs-lang=csharp), and [GraphQL](https://ej2.syncfusion.com/angular/documentation/grid/connecting-to-adaptors/graphql-adaptor), the `UrlAdaptor` is particularly useful for the scenarios where a custom API service with unique logic for handling data and CRUD operations is in place. This approach allows for custom handling of data and CRUD operations, and the resultant data returned in the `result` and `count` format for display in the Grid.
+
+* **Using CustomAdaptor**
+
+The [CustomAdaptor](https://ej2.syncfusion.com/angular/documentation/grid/connecting-to-adaptors/custom-adaptor) serves as a mediator between the UI component and the database for data binding. While the data source from the database can be directly bound to the Syncfusion Angular Grid locally using the `dataSource` property, the `CustomAdaptor` approach is preferred as it allows for customization of both data operations and CRUD operations according to specific requirements. In this approach, for every action in the Grid, a corresponding request with action details is sent to the `CustomAdaptor`. The Grid provides predefined methods to perform data operations such as **searching**, **filtering**, **sorting**, **aggregation**, **paging** and **grouping**. Alternatively, your own custom methods can be employed to execute operations and return the data in the `result` and `count` format for displaying in the Grid. Additionally, for CRUD operations, predefined methods can be overridden to provide custom functionality. Further details on this can be found in the latter part of the documentation.
+
+## Binding data from SQLite Server using an API service
+
+This section describes step by step process how to retrieve data from a SQLite Server using an API service and bind it to the Grid.
+
+### Creating an API service
+
+**1.** Open Visual Studio and create an Angular and ASP.NET Core project named **Grid_SQLite**. To create an Angular and ASP.NET Core application, follow the documentation [link](https://learn.microsoft.com/en-us/visualstudio/javascript/tutorial-asp-net-core-with-angular?view=vs-2022) for detailed steps.
+
+**2.** To connect a SQLite Server database using the SQLite driver in your application, you need to install the [Microsoft.Data.Sqlite](https://www.nuget.org/packages/Microsoft.Data.Sqlite/) NuGet package. To add **Microsoft.Data.Sqlite** in the app, open the NuGet package manager in Visual Studio (Tools → NuGet Package Manager → Manage NuGet Packages for Solution), search and install it.
+
+**3.** Create an API controller (aka, GridController.cs) file under **Controllers** folder that helps to establish data communication with the Grid.
+
+**4.** In an API controller (aka, GridController), connect to SQLite Server. In the **GetOrderData()** method **SqliteConnection** helps to connect the SQLite Server database. Next, the **SqliteCommand** is used to retrieve the desired collection from the database. Then populate the data collection from the **SqliteCommand** into a list using the **Read** method of **SqliteDataReader** as shown in the following code snippet.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+using Microsoft.AspNetCore.Mvc;
+using System.ComponentModel.DataAnnotations;
+using System.Data;
+using Syncfusion.EJ2.Base;
+using Microsoft.Data.Sqlite;
+
+namespace Grid_SQLite.Server.Controllers
+{
+ [ApiController]
+ public class GridController : ControllerBase
+ {
+ string ConnectionString = @"";
+
+ ///
+ /// Processes the DataManager request to perform searching, filtering, sorting, and paging operations.
+ ///
+ /// Contains the details of the data operation requested.
+ /// Returns a JSON object along with the total record count.
+ [HttpPost]
+ [Route("api/[controller]")]
+ public object Post([FromBody] DataManagerRequest DataManagerRequest)
+ {
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+ }
+
+ ///
+ /// Retrieves the order data from the database.
+ ///
+ /// Returns a list of orders fetched from the database.
+ [HttpGet]
+ [Route("api/[controller]")]
+ public List GetOrderData()
+ {
+ // SQL query to fetch all records from the orders table and sort them by OrderID.
+ string queryStr = "SELECT * FROM Orders ORDER BY OrderID;";
+
+ // Creates an empty list to store the retrieved orders from the database.
+ List DataSource = new List();
+
+ // Establishes a connection to the SQLite database using the provided connection string.
+ SqliteConnection Connection = new SqliteConnection(ConnectionString);
+
+ // Opens the database connection to enable SQL queries.
+ Connection.Open();
+
+ //Using SqliteCommand and query create connection with database.
+ SqliteCommand Command = new SqliteCommand(queryStr, Connection);
+
+ // Execute the SQLite command and retrieve data using SqliteDataReader.
+ using (SqliteDataReader reader = Command.ExecuteReader())
+ {
+ while (reader.Read())
+ {
+ Orders order = new Orders
+ {
+ OrderID = reader.GetInt32(reader.GetOrdinal("OrderID")),
+ CustomerID = reader.GetString(reader.GetOrdinal("CustomerID")),
+ EmployeeID = reader.GetInt32(reader.GetOrdinal("EmployeeID")),
+ ShipCity = reader.GetString(reader.GetOrdinal("ShipCity")),
+ Freight = reader.GetDecimal(reader.GetOrdinal("Freight"))
+ };
+ DataSource.Add(order);
+ }
+ }
+ return DataSource;
+ }
+
+ public class Orders
+ {
+ [Key]
+ public int? OrderID { get; set; }
+ public string? CustomerID { get; set; }
+ public int? EmployeeID { get; set; }
+ public decimal? Freight { get; set; }
+ public string? ShipCity { get; set; }
+ }
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**5.** Run the application and it will be hosted within the URL `https://localhost:xxxx`.
+
+**6.** Finally, the retrieved data from SQLite Server database which is in the form of list can be found in an API controller available in the URL link `https://localhost:xxxx/api/Grid`, as shown in the browser page below.
+
+
+
+### Connecting Syncfusion Angular Grid to an API service
+
+To integrate Syncfusion Angular Grid into your Angular and ASP.NET Core project using Visual Studio, follow the below steps:
+
+**Step 1: Install Syncfusion Package**
+
+Open your terminal in the project's client folder and install the required Syncfusion packages using npm:
+
+```bash
+npm install @syncfusion/ej2-angular-grids --save
+npm install @syncfusion/ej2-data --save
+```
+
+**Step 2: Import Grid Module**
+
+In the `app.module.ts` file, import the **GridModule** from the `@syncfusion/ej2-angular-grids` package:
+
+**Step 3: Adding CSS reference**
+
+Include the necessary CSS files in your `styles.css` file to style the Syncfusion Angular component:
+
+{% tabs %}
+{% highlight css tabtitle="styles.css" %}
+
+@import '../node_modules/@syncfusion/ej2-base/styles/material.css';
+@import '../node_modules/@syncfusion/ej2-buttons/styles/material.css';
+@import '../node_modules/@syncfusion/ej2-calendars/styles/material.css';
+@import '../node_modules/@syncfusion/ej2-dropdowns/styles/material.css';
+@import '../node_modules/@syncfusion/ej2-inputs/styles/material.css';
+@import '../node_modules/@syncfusion/ej2-navigations/styles/material.css';
+@import '../node_modules/@syncfusion/ej2-popups/styles/material.css';
+@import '../node_modules/@syncfusion/ej2-splitbuttons/styles/material.css';
+@import '../node_modules/@syncfusion/ej2-angular-grids/styles/material.css';
+
+{% endhighlight %}
+{% endtabs %}
+
+**2.** In your component file (e.g., app.component.ts), import `DataManager` and `UrlAdaptor` from `@syncfusion/ej2-data`. Create a [DataManager](https://ej2.syncfusion.com/angular/documentation/data/getting-started) instance specifying the URL of your API endpoint(https:localhost:xxxx/api/Grid) using the `url` property and set the adaptor `UrlAdaptor`.
+
+**3.** The `DataManager` offers multiple adaptor options to connect with remote database based on an API service. Below is an example of the `UrlAdaptor` configuration where an API service are set up to return the resulting data in the `result` and `count` format.
+
+**4.** The `UrlAdaptor` acts as the base adaptor for interacting with remote data service. Most of the built-in adaptors are derived from the `UrlAdaptor`.
+
+{% tabs %}
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
+import { GridComponent, GridModule } from '@syncfusion/ej2-angular-grids';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new UrlAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+
+{% highlight cs tabtitle="GridController.cs" %}
+
+using Microsoft.AspNetCore.Mvc;
+using System.ComponentModel.DataAnnotations;
+using System.Data;
+using Syncfusion.EJ2.Base;
+using Microsoft.Data.Sqlite;
+
+namespace Grid_SQLite.Server.Controllers
+{
+ [ApiController]
+ public class GridController : ControllerBase
+ {
+ string ConnectionString = @"";
+
+ ///
+ /// Processes the DataManager request to perform searching, filtering, sorting, and paging operations.
+ ///
+ /// Contains the details of the data operation requested.
+ /// Returns a JSON object along with the total record count.
+ [HttpPost]
+ [Route("api/[controller]")]
+ public object Post([FromBody] DataManagerRequest DataManagerRequest)
+ {
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+ }
+
+ ///
+ /// Retrieves the order data from the database.
+ ///
+ /// Returns a list of orders fetched from the database.
+ [HttpGet]
+ [Route("api/[controller]")]
+ public List GetOrderData()
+ {
+ // SQL query to fetch all records from the orders table and sort them by OrderID.
+ string queryStr = "SELECT * FROM Orders ORDER BY OrderID;";
+
+ // Creates an empty list to store the retrieved orders from the database.
+ List DataSource = new List();
+
+ // Establishes a connection to the SQLite database using the provided connection string.
+ SqliteConnection Connection = new SqliteConnection(ConnectionString);
+
+ // Opens the database connection to enable SQL queries.
+ Connection.Open();
+
+ //Using SqliteCommand and query create connection with database.
+ SqliteCommand Command = new SqliteCommand(queryStr, Connection);
+
+ // Execute the SQLite command and retrieve data using SqliteDataReader.
+ using (SqliteDataReader reader = Command.ExecuteReader())
+ {
+ while (reader.Read())
+ {
+ Orders order = new Orders
+ {
+ OrderID = reader.GetInt32(reader.GetOrdinal("OrderID")),
+ CustomerID = reader.GetString(reader.GetOrdinal("CustomerID")),
+ EmployeeID = reader.GetInt32(reader.GetOrdinal("EmployeeID")),
+ ShipCity = reader.GetString(reader.GetOrdinal("ShipCity")),
+ Freight = reader.GetDecimal(reader.GetOrdinal("Freight"))
+ };
+ DataSource.Add(order);
+ }
+ }
+ return DataSource;
+ }
+
+ public class Orders
+ {
+ [Key]
+ public int? OrderID { get; set; }
+ public string? CustomerID { get; set; }
+ public int? EmployeeID { get; set; }
+ public decimal? Freight { get; set; }
+ public string? ShipCity { get; set; }
+ }
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+
+> Replace https://localhost:xxxx/api/Grid with the actual **URL** of your API endpoint that provides the data in a consumable format (e.g., JSON).
+
+**5.** Run the application in Visual Studio. It will be accessible via a URL like **https://localhost:xxxx**.
+
+> Ensure your API service is configured to handle CORS (Cross-Origin Resource Sharing) if necessary.
+ ```cs
+ [program.cs]
+ builder.Services.AddCors(options =>
+ {
+ options.AddDefaultPolicy(builder =>
+ {
+ builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
+ });
+ });
+ var app = builder.Build();
+ app.UseCors();
+ ```
+
+> * The Syncfusion Angular Grid provides built-in support for handling various data operations such as searching, sorting, filtering, aggregate and paging on the server-side. These operations can be handled using methods such as `PerformSearching`, `PerformFiltering`, `PerformSorting`, `PerformTake` and `PerformSkip` available in the [Syncfusion.EJ2.AspNet.Core](https://www.nuget.org/packages/Syncfusion.EJ2.AspNet.Core/) package. Let’s explore how to manage these data operations using the `UrlAdaptor`.
+> * In an API service project, add `Syncfusion.EJ2.AspNet.Core` by opening the NuGet package manager in Visual Studio (Tools → NuGet Package Manager → Manage NuGet Packages for Solution), search and install it.
+> * To access `DataManagerRequest` and `QueryableOperation`, import `Syncfusion.EJ2.Base` in `GridController.cs` file.
+
+### Handling searching operation
+
+To handle searching operation, ensure that your API endpoint supports custom searching criteria. Implement the searching logic on the server-side using the `PerformSearching` method from the `QueryableOperation` class. This allows the custom data source to undergo searching based on the criteria specified in the incoming `DataManagerRequest` object.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform searching operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the searched data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Handling searching operation.
+ if (DataManagerRequest.Search != null && DataManagerRequest.Search.Count > 0)
+ {
+ DataSource = queryableOperation.PerformSearching(DataSource, DataManagerRequest.Search);
+ //Add custom logic here if needed and remove above method.
+ }
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
+import { GridComponent, ToolbarItems, GridModule, ToolbarService } from '@syncfusion/ej2-angular-grids';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [ToolbarService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+ public toolbar?: ToolbarItems[];
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new UrlAdaptor()
+ });
+ this.toolbar = ['Search'];
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling filtering operation
+
+To handle filtering operation, ensure that your API endpoint supports custom filtering criteria. Implement the filtering logic on the server-side using the `PerformFiltering` method from the `QueryableOperation` class. This allows the custom data source to undergo filtering based on the criteria specified in the incoming `DataManagerRequest` object.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform filtering operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the filtered data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Handling filtering operation.
+ if (DataManagerRequest.Where != null && DataManagerRequest.Where.Count > 0)
+ {
+ foreach (WhereFilter condition in DataManagerRequest.Where)
+ {
+ foreach (WhereFilter predicate in condition.predicates)
+ {
+ DataSource = queryableOperation.PerformFiltering(DataSource, DataManagerRequest.Where, predicate.Operator);
+ //Add custom logic here if needed and remove above method.
+ }
+ }
+ }
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
+mport { GridComponent, FilterService, GridModule } from '@syncfusion/ej2-angular-grids';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [FilterService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid')public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new UrlAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling sorting operation
+
+To handle sorting operation, ensure that your API endpoint supports custom sorting criteria. Implement the sorting logic on the server-side using the `PerformSorting` method from the `QueryableOperation` class. This allows the custom data source to undergo sorting based on the criteria specified in the incoming `DataManagerRequest` object.
+
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform sorting operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the sorted data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Handling sorting operation.
+ if (DataManagerRequest.Sorted != null && DataManagerRequest.Sorted.Count > 0)
+ {
+ DataSource = queryableOperation.PerformSorting(DataSource, DataManagerRequest.Sorted);
+ //Add custom logic here if needed and remove above method.
+ }
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
+import { GridComponent, SortService, GridModule } from '@syncfusion/ej2-angular-grids';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [SortService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new UrlAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling paging operation
+
+To handle paging operation, ensure that your API endpoint supports custom paging criteria. Implement the paging logic on the server-side using the `PerformTake` and `PerformSkip`method from the `QueryableOperation` class. This allows the custom data source to undergo paging based on the criteria specified in the incoming `DataManagerRequest` object.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform paging operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the paginated data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Handling paging operation.
+ if (DataManagerRequest.Skip != 0)
+ {
+ DataSource = queryableOperation.PerformSkip(DataSource, DataManagerRequest.Skip);
+ //Add custom logic here if needed and remove above method.
+ }
+ if (DataManagerRequest.Take != 0)
+ {
+ DataSource = queryableOperation.PerformTake(DataSource, DataManagerRequest.Take);
+ //Add custom logic here if needed and remove above method.
+ }
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
+import { GridComponent, PageService, GridModule } from '@syncfusion/ej2-angular-grids';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [PageService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new UrlAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling CRUD operations
+
+The Syncfusion Angular Grid seamlessly integrates CRUD (Create, Read, Update, and Delete) operations with server-side controller actions through specific properties: `insertUrl`, `removeUrl`, `updateUrl` and `batchUrl`. These properties enable the Grid to communicate with the data service for every Grid action, facilitating server-side operations.
+
+**CRUD Operations Mapping**
+
+CRUD operations within the Grid can be mapped to server-side controller actions using specific properties:
+
+1. **insertUrl**: Specifies the URL for inserting new data.
+2. **removeUrl**: Specifies the URL for removing existing data.
+3. **updateUrl**: Specifies the URL for updating existing data.
+4. **batchUrl**: Specifies the URL for batch editing.
+
+To enable editing in Grid, refer to the editing [documentation](https://ej2.syncfusion.com/angular/documentation/grid/editing/edit). In the below example, the inline edit [mode](https://ej2.syncfusion.com/angular/documentation/api/grid/editSettings/#mode) is enabled and [toolbar](https://helpej2.syncfusion.com/angular/documentation/api/grid/#toolbar) property is configured to display toolbar items for editing purposes.
+
+{% tabs %}
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager, UrlAdaptor } from '@syncfusion/ej2-data';
+import { GridComponent, EditSettingsModel,GridModule, ToolbarItems,EditService, ToolbarService } from '@syncfusion/ej2-angular-grids';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [EditService, ToolbarService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+ public editSettings?: EditSettingsModel;
+ public toolbar?: ToolbarItems[];
+ public employeeIDRules?: Object;
+ public customerIDRules?: Object;
+ public freightRules?: Object;
+ public shipCityRules?: Object;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ insertUrl: 'https://localhost:xxxx/api/Grid/Insert',
+ updateUrl: 'https://localhost:xxxx/api/Grid/Update',
+ removeUrl: 'https://localhost:xxxx/api/Grid/Remove',
+ // Enable batch URL when batch editing is enabled.
+ //batchUrl: 'https://localhost:xxxx/api/Grid/BatchUpdate',
+ adaptor: new UrlAdaptor()
+ });
+ this.employeeIDRules = { required: true, number: true };
+ this.customerIDRules = { required: true };
+ this.freightRules = { required: true, min: 1, max: 1000 };
+ this.shipCityRules = { required: true };
+ this.toolbar = ['Add', 'Update', 'Delete', 'Cancel', 'Search'];
+ this.editSettings = { allowAdding: true, allowDeleting: true, allowEditing: true, mode: 'Normal' };
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+{% endtabs %}
+
+> * Normal/Inline editing is the default edit [mode](https://ej2.syncfusion.com/angular/documentation/api/grid/editSettings/#mode) for the Grid. To enable CRUD operations, ensure that the [isPrimaryKey](https://ej2.syncfusion.com/angular/documentation/api/grid/column/#isprimarykey) property is set to **true** for a specific Grid column, ensuring that its value is unique.
+> * If database has an auto generated column, ensure to define [isIdentity](https://ej2.syncfusion.com/angular/documentation/api/grid/column/#isidentity) property of Grid column to disable them during adding or editing operations.
+
+**Insert Operation:**
+
+To insert a new row, simply click the **Add** toolbar button. The new record edit form will be displayed as shown below. Upon clicking the **Update** toolbar button, record will inserted into the **Orders** table by calling the following **POST** method of an API.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Inserts a new data item into the data collection.
+///
+/// It contains the new record detail which is need to be inserted.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/Insert")]
+public void Insert([FromBody] CRUDModel value)
+{
+ //Create query to insert the specific into the database by accessing its properties.
+ string queryStr = $"Insert into Orders(CustomerID,Freight,ShipCity,EmployeeID) values('{value.value.CustomerID}','{value.value.Freight}','{value.value.ShipCity}','{value.value.EmployeeID}')";
+
+ // Establishes a connection to the SQLite database using the provided connection string.
+ SqliteConnection Connection = new SqliteConnection(ConnectionString);
+
+ // Opens the database connection to execute queries.
+ Connection.Open();
+
+ //Execute the SQLite command.
+ SqliteCommand Command = new SqliteCommand(queryStr, Connection);
+
+ //Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the query.
+ Connection.Close();
+
+ //Add custom logic here if needed and remove above method.
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**Update Operation:**
+
+To edit a row, first select desired row and click the **Edit** toolbar button. The edit form will be displayed and proceed to modify any column value as per your requirement. Clicking the **Update** toolbar button will update the edit record in the **Orders** table by involving the following **Post** method of an API.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Update a existing data item from the data collection.
+///
+/// It contains the updated record detail which is need to be updated.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/Update")]
+public void Update([FromBody] CRUDModel value)
+{
+ //Create query to update the changes into the database by accessing its properties.
+ string queryStr = $"Update Orders set CustomerID='{value.value.CustomerID}', Freight='{value.value.Freight}',EmployeeID='{value.value.EmployeeID}',ShipCity='{value.value.ShipCity}' where OrderID='{value.value.OrderID}'";
+
+ // Establishes a connection to the SQLite database using the provided connection string.
+ SqliteConnection Connection = new SqliteConnection(ConnectionString);
+
+ // Opens the database connection to execute queries.
+ Connection.Open();
+
+ //Execute the SQLite command.
+ SqliteCommand Command = new SqliteCommand(queryStr, Connection);
+
+ //Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the query.
+ Connection.Close();
+
+ //Add custom logic here if needed and remove above method.
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**Delete Operation:**
+
+To delete a row, simply select the desired row and click the **Delete** toolbar button. This action will trigger a **DELETE** request to an API, containing the primary key value of the selected record. As a result corresponding record will be removed from the **Orders** table.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Remove a specific data item from the data collection.
+///
+/// It contains the specific record detail which is need to be removed.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/Remove")]
+public void Remove([FromBody] CRUDModel value)
+{
+ //Create query to remove the specific from database by passing the primary key column value.
+ string queryStr = $"Delete from Orders where OrderID={value.key}";
+
+ // Establishes a connection to the SQLite database using the provided connection string.
+ SqliteConnection Connection = new SqliteConnection(ConnectionString);
+
+ // Opens the database connection to execute queries.
+ Connection.Open();
+
+ //Execute the SQLite command.
+ SqliteCommand Command = new SqliteCommand(queryStr, Connection);
+
+ //Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the query.
+ Connection.Close();
+
+ //Add custom logic here if needed and remove above method.
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**Batch Operation:**
+
+To perform batch operation, define the edit [mode](https://ej2.syncfusion.com/angular/documentation/api/grid/editSettings/#mode) as **Batch** and specify the `batchUrl` property in the `DataManager`. Use the **Add** toolbar button to insert new row in batch editing mode. To edit a cell, double-click the desired cell and update the value as required. To delete a record, simply select the record and press the **Delete** toolbar button. Now, all CRUD operations will be executed in batch editing mode. Clicking the **Update** toolbar button will update the newly added, edited, or deleted records from the **Orders** table using a single API **POST** request.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Batch update (Insert, Update, and Delete) a collection of data items from the data collection.
+///
+/// The set of information along with details about the CRUD actions to be executed from the database.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/BatchUpdate")]
+public IActionResult BatchUpdate([FromBody] CRUDModel value)
+{
+ if (value.changed != null && value.changed.Count > 0)
+ {
+ foreach (Orders Record in (IEnumerable)value.changed)
+ {
+ //Create query to update the changes into the database by accessing its properties.
+ string queryStr = $"Update Orders set CustomerID='{Record.CustomerID}', Freight='{Record.Freight}',EmployeeID='{Record.EmployeeID}',ShipCity='{Record.ShipCity}' where OrderID='{Record.OrderID}'";
+
+ // Establishes a connection to the SQLite database using the provided connection string.
+ SqliteConnection Connection = new SqliteConnection(ConnectionString);
+
+ // Opens the database connection to execute queries.
+ Connection.Open();
+
+ //Execute the SQLite command.
+ SqliteCommand Command = new SqliteCommand(queryStr, Connection);
+
+ //Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the query.
+ Connection.Close();
+
+ //Add custom logic here if needed and remove above method.
+ }
+ }
+ if (value.added != null && value.added.Count > 0)
+ {
+ foreach (Orders Record in (IEnumerable)value.added)
+ {
+ //Create query to insert the specific into the database by accessing its properties.
+ string queryStr = $"Insert into Orders(CustomerID,Freight,ShipCity,EmployeeID) values('{Record.CustomerID}','{Record.Freight}','{Record.ShipCity}','{Record.EmployeeID}')";
+
+ // Establishes a connection to the SQLite database using the provided connection string.
+ SqliteConnection Connection = new SqliteConnection(ConnectionString);
+
+ // Opens the database connection to execute queries.
+ Connection.Open();
+
+ //Execute the SQLite command.
+ SqliteCommand Command = new SqliteCommand(queryStr, Connection);
+
+ //Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the query.
+ Connection.Close();
+
+ //Add custom logic here if needed and remove above method.
+ }
+ }
+ if (value.deleted != null && value.deleted.Count > 0)
+ {
+ foreach (Orders Record in (IEnumerable)value.deleted)
+ {
+ //Create query to remove the specific from database by passing the primary key column value.
+ string queryStr = $"Delete from Orders where OrderID={Record.OrderID}";
+
+ // Establishes a connection to the SQLite database using the provided connection string.
+ SqliteConnection Connection = new SqliteConnection(ConnectionString);
+
+ // Opens the database connection to execute queries.
+ Connection.Open();
+
+ //Execute the SQLite command.
+ SqliteCommand Command = new SqliteCommand(queryStr, Connection);
+
+ //Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the query.
+ Connection.Close();
+
+ //Add custom logic here if needed and remove above method.
+ }
+ }
+ return new JsonResult(value);
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+When you run the application, the resultant Grid will look like this
+
+
+
+> Please find the sample in this [GitHub location](https://github.com/SyncfusionExamples/connecting-databases-to-angular-grid/tree/master/Binding%20SQLite%20using%20UrlAdaptor/Grid_SQLite).
+
+## Binding data from SQLite Server using CustomAdaptor
+
+This section describes step by step process how to retrieve data from a SQLite Server using [CustomAdaptor](https://ej2.syncfusion.com/angular/documentation/grid/connecting-to-adaptors/custom-adaptor) and bind it to the Syncfusion Angular Grid.
+
+**1.** To create a simple Grid, the procedure is explained in the above-mentioned topic on [Connecting Syncfusion Angular Grid to an API service](#connecting-syncfusion-angular-grid-to-an-api-service)
+
+**2.** To connect a SQLite Server database using the SQLite driver in your application, you need to install the [Microsoft.Data.Sqlite](https://www.nuget.org/packages/Microsoft.Data.Sqlite/) NuGet package. To add **Microsoft.Data.Sqlite** in the app, open the NuGet package manager in Visual Studio (Tools → NuGet Package Manager → Manage NuGet Packages for Solution), search and install it.
+
+**3.** If you intend to inject your own service into the `CustomAdaptor` and utilize it, you can achieve this as follows:
+
+ * Create a `CustomAdaptor` that extends the `UrlAdaptor` class.
+ * Override the `processResponse` method to process server responses.
+
+**4.** Within the `processResponse` method of `CustomAdaptor`, fetch data by calling the **GetOrderData** method.
+
+
+ * In this **GetOrderData** method, the SQLite Server database data is fetch by using the **SqliteDataReader** class.
+ * Employ the `processResponse` method to asynchronously iterate over the results retrieved by executing the SQL query with **ExecuteReaderAsync** method, gathering the data into a list.
+ * Finally, return the response as a `result` and `count` pair object in the `processResponse` method to bind the data to the Grid.
+
+{% tabs %}
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager } from '@syncfusion/ej2-data';
+import { GridComponent, GridModule } from '@syncfusion/ej2-angular-grids';
+import { CustomAdaptor } from './CustomAdaptor'
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid',
+ adaptor: new CustomAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="CustomAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+}
+
+{% endhighlight %}
+
+{% highlight cs tabtitle="GridController.cs" %}
+
+using Microsoft.AspNetCore.Mvc;
+using System.ComponentModel.DataAnnotations;
+using System.Data;
+using Syncfusion.EJ2.Base;
+using Microsoft.Data.Sqlite;
+
+namespace Grid_SQLite.Server.Controllers
+{
+ [ApiController]
+ public class GridController : ControllerBase
+ {
+ string ConnectionString = @"";
+
+ ///
+ /// Processes the DataManager request to perform searching, filtering, sorting, and paging operations.
+ ///
+ /// Contains the details of the data operation requested.
+ /// Returns a JSON object along with the total record count.
+ [HttpPost]
+ [Route("api/[controller]")]
+ public object Post([FromBody] DataManagerRequest DataManagerRequest)
+ {
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+ }
+
+ ///
+ /// Retrieves the order data from the database.
+ ///
+ /// Returns a list of orders fetched from the database.
+ [HttpGet]
+ [Route("api/[controller]")]
+ public List GetOrderData()
+ {
+ // SQL query to fetch all records from the orders table and sort them by OrderID.
+ string queryStr = "SELECT * FROM Orders ORDER BY OrderID;";
+
+ // Creates an empty list to store the retrieved orders from the database.
+ List DataSource = new List();
+
+ // Establishes a connection to the SQLite database using the provided connection string.
+ SqliteConnection Connection = new SqliteConnection(ConnectionString);
+
+ // Opens the database connection to enable SQL queries.
+ Connection.Open();
+
+ //Using SqliteCommand and query create connection with database.
+ SqliteCommand Command = new SqliteCommand(queryStr, Connection);
+
+ // Execute the SQLite command and retrieve data using SqliteDataReader.
+ using (SqliteDataReader reader = Command.ExecuteReader())
+ {
+ while (reader.Read())
+ {
+ Orders order = new Orders
+ {
+ OrderID = reader.GetInt32(reader.GetOrdinal("OrderID")),
+ CustomerID = reader.GetString(reader.GetOrdinal("CustomerID")),
+ EmployeeID = reader.GetInt32(reader.GetOrdinal("EmployeeID")),
+ ShipCity = reader.GetString(reader.GetOrdinal("ShipCity")),
+ Freight = reader.GetDecimal(reader.GetOrdinal("Freight"))
+ };
+ DataSource.Add(order);
+ }
+ }
+ return DataSource;
+ }
+
+ public class Orders
+ {
+ [Key]
+ public int? OrderID { get; set; }
+ public string? CustomerID { get; set; }
+ public int? EmployeeID { get; set; }
+ public decimal? Freight { get; set; }
+ public string? ShipCity { get; set; }
+ }
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+> * The `DataManagerRequest` encompasses details about the Grid actions such as searching, filtering, sorting, aggregate, paging and grouping.
+
+### Handling searching operation
+
+When utilizing the `CustomAdaptor` in Angular, managing the searching operation involves overriding the `processResponse` method of the `UrlAdaptor` class.
+
+In the code example below, searching a custom data source can be accomplished by employing the built-in `PerformSearching` method of the `QueryableOperation` class. Alternatively, you can implement your own method for searching operation and bind the resultant data to the Grid.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform searching operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the searched data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Handling searching operation.
+ if (DataManagerRequest.Search != null && DataManagerRequest.Search.Count > 0)
+ {
+ DataSource = queryableOperation.PerformSearching(DataSource, DataManagerRequest.Search);
+ //Add custom logic here if needed and remove above method.
+ }
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager } from '@syncfusion/ej2-data';
+import { GridComponent, ToolbarItems, ToolbarService, GridModule} from '@syncfusion/ej2-angular-grids';
+import { CustomAdaptor } from './CustomAdaptor'
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [ToolbarService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+ public toolbar?: ToolbarItems[];
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new CustomAdaptor()
+ });
+ this.toolbar = ['Search'];
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="customAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling filtering operation
+
+When utilizing the `CustomAdaptor` in Angular, managing the filtering operation involves overriding the `processResponse` method of the `UrlAdaptor` class.
+
+In the code example below, filtering a custom data source can be achieved by utilizing the built-in `PerformFiltering` method of the `QueryableOperation` class. Alternatively, you can implement your own method for filtering operation and bind the resulting data to the Grid.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform filtering operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the filtered data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Handling filtering operation.
+ if (DataManagerRequest.Where != null && DataManagerRequest.Where.Count > 0)
+ {
+ foreach (WhereFilter condition in DataManagerRequest.Where)
+ {
+ foreach (WhereFilter predicate in condition.predicates)
+ {
+ DataSource = queryableOperation.PerformFiltering(DataSource, DataManagerRequest.Where, predicate.Operator);
+ //Add custom logic here if needed and remove above method.
+ }
+ }
+ }
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager } from '@syncfusion/ej2-data';
+import { GridComponent, FilterService, GridModule } from '@syncfusion/ej2-angular-grids';
+import { CustomAdaptor } from './CustomAdaptor'
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [FilterService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid')public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new CustomAdaptor()
+ });
+ }
+}
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="customAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling sorting operation
+
+When utilizing the `CustomAdaptor` in Angular, managing the sorting operation involves overriding the `processResponse` method of the `UrlAdaptor` class.
+
+In the code example below, sorting a custom data source can be accomplished by employing the built-in `PerformSorting` method of the `QueryableOperation` class. Alternatively, you can implement your own method for sorting operation and bind the resulting data to the Grid.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform sorting operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the sorted data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Handling sorting operation.
+ if (DataManagerRequest.Sorted != null && DataManagerRequest.Sorted.Count > 0)
+ {
+ DataSource = queryableOperation.PerformSorting(DataSource, DataManagerRequest.Sorted);
+ //Add custom logic here if needed and remove above method.
+ }
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager } from '@syncfusion/ej2-data';
+import { GridComponent, SortService, GridModule } from '@syncfusion/ej2-angular-grids';
+import { CustomAdaptor } from './CustomAdaptor'
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [SortService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new CustomAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="customAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling paging operation
+
+When utilizing the `CustomAdaptor` in Angular, managing the paging operation involves overriding the `processResponse` method of the `UrlAdaptor` class.
+
+In the code example below, paging a custom data source can be achieved by utilizing the built-in `PerformTake` and `PerformSkip` method of the `QueryableOperation` class. Alternatively, you can use your own method for paging operation and bind the resulting data to the Grid.
+
+{% tabs %}
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Processes the DataManager request to perform paging operation.
+///
+/// Contains the details of the data operation requested.
+/// Returns a JSON object with the paginated data along with the total record count.
+[HttpPost]
+[Route("api/[controller]")]
+public object Post([FromBody] DataManagerRequest DataManagerRequest)
+{
+ // Retrieve data from the data source (e.g., database).
+ IQueryable DataSource = GetOrderData().AsQueryable();
+
+ // Initialize QueryableOperation instance.
+ QueryableOperation queryableOperation = new QueryableOperation();
+
+ // Get the total count of records.
+ int totalRecordsCount = DataSource.Count();
+
+ // Handling paging operation.
+ if (DataManagerRequest.Skip != 0)
+ {
+ DataSource = queryableOperation.PerformSkip(DataSource, DataManagerRequest.Skip);
+ //Add custom logic here if needed and remove above method.
+ }
+ if (DataManagerRequest.Take != 0)
+ {
+ DataSource = queryableOperation.PerformTake(DataSource, DataManagerRequest.Take);
+ //Add custom logic here if needed and remove above method.
+ }
+
+ // Return data based on the request.
+ return new { result = DataSource, count = totalRecordsCount };
+}
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager } from '@syncfusion/ej2-data';
+import { GridComponent, PageService, GridModule } from '@syncfusion/ej2-angular-grids';
+import { CustomAdaptor } from './CustomAdaptor'
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [PageService],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid', // Replace your hosted link.
+ adaptor: new CustomAdaptor()
+ });
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+
+{% highlight ts tabtitle="customAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+### Handling CRUD operations
+
+To enable editing in the Syncfusion Angular Grid, utilize the [editSettings](https://ej2.syncfusion.com/angular/documentation/api/grid/editSettings/) property. The Grid offers multiple edit modes including the Inline/Normal, Dialog and Batch editing. For more details, refer to the Grid [editing](https://ej2.syncfusion.com/angular/documentation/grid/editing/edit) documentation.
+
+In this scenario, the inline edit [mode](https://ej2.syncfusion.com/angular/documentation/api/grid/editSettings/#mode) and [toolbar](https://ej2.syncfusion.com/angular/documentation/api/grid/#toolbar) property configured to display toolbar items for editing purpose.
+
+{% tabs %}
+{% highlight ts tabtitle="app.component.ts" %}
+
+import { Component, ViewChild } from '@angular/core';
+import { DataManager } from '@syncfusion/ej2-data';
+import { GridComponent, EditSettingsModel, ToolbarItems,EditService, ToolbarService,GridModule } from '@syncfusion/ej2-angular-grids';
+import { CustomAdaptor } from './CustomAdaptor'
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ standalone: true,
+ providers: [EditService, ToolbarService ],
+ imports: [GridModule],
+})
+export class AppComponent {
+ @ViewChild('grid') public grid?: GridComponent;
+ public data?: DataManager;
+ public editSettings?: EditSettingsModel;
+ public toolbar?: ToolbarItems[];
+ public employeeIDRules?: Object;
+ public customerIDRules?: Object;
+ public freightRules?: Object;
+ public shipCityRules?: Object;
+
+ public ngOnInit(): void {
+ this.data = new DataManager({
+ url: 'https://localhost:xxxx/api/Grid',
+ insertUrl: 'https://localhost:xxxx/api/Grid/Insert',
+ updateUrl: 'https://localhost:xxxx/api/Grid/Update',
+ removeUrl: 'https://localhost:xxxx/api/Grid/Remove',
+ / Enable batch URL when batch editing is enabled.
+ //batchUrl: 'https://localhost:xxxx/api/Grid/BatchUpdate',
+ adaptor: new CustomAdaptor()
+ });
+ this.employeeIDRules = { required: true, number: true };
+ this.customerIDRules = { required: true };
+ this.freightRules = { required: true, min: 1, max: 1000 };
+ this.shipCityRules = { required: true };
+ this.toolbar = ['Add', 'Update', 'Delete', 'Cancel', 'Search'];
+ this.editSettings = { allowAdding: true, allowDeleting: true, allowEditing: true, mode: 'Normal' };
+ }
+}
+
+{% endhighlight %}
+
+{% highlight html tabtitle="app.component.html" %}
+
+
+
+
+
+
+
+
+
+
+
+{% endhighlight %}
+{% endtabs %}
+
+> * Normal/Inline editing is the default edit `mode` for the Grid. To enable CRUD operations, ensure that the [isPrimaryKey](https://ej2.syncfusion.com/angular/documentation/api/grid/column/#isprimarykey) property is set to **true** for a specific Grid column, ensuring that its value is unique.
+> * If database has an auto generated column, ensure to define [isIdentity](https://ej2.syncfusion.com/angular/documentation/api/grid/column/#isidentity) property of Grid column to disable them during adding or editing operations.
+
+The CRUD operations can be performed and customized on our own by overriding the following CRUD methods of the `UrlAdaptor`
+
+* insert
+* remove
+* update
+* batchRequest
+
+Let’s see how to perform CRUD operation using SQLite Server data with Grid.
+
+**Insert Operation:**
+
+To execute the insert operation, you will need to override the `insert` method of the `CustomAdaptor`. Then, integrate the following code snippet into the `CustomAdaptor` class. The below code snippet demonstrated how to handle the insertion of new records within the `insert` method of `CustomAdaptor`. Modify the logic within this method according to the requirements of your application.
+
+{% tabs %}
+{% highlight ts tabtitle="CustomAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+
+ public override insert(dm: any, data: any): any {
+ return {
+ url: dm.dataSource.insertUrl || dm.dataSource.url,
+ data: JSON.stringify({
+ __RequestVerificationToken: "Syncfusion",
+ value: data,
+ action: 'insert'
+ }),
+ type: 'POST'
+ };
+ }
+}
+
+{% endhighlight %}
+
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Inserts a new data item into the data collection.
+///
+/// It contains the new record detail which is need to be inserted.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/Insert")]
+public void Insert([FromBody] CRUDModel value)
+{
+ //Create query to insert the specific into the database by accessing its properties.
+ string queryStr = $"Insert into Orders(CustomerID,Freight,ShipCity,EmployeeID) values('{value.value.CustomerID}','{value.value.Freight}','{value.value.ShipCity}','{value.value.EmployeeID}')";
+
+ // Establishes a connection to the SQLite database using the provided connection string.
+ SqliteConnection Connection = new SqliteConnection(ConnectionString);
+
+ // Opens the database connection to execute queries.
+ Connection.Open();
+
+ //Execute the SQLite command.
+ SqliteCommand Command = new SqliteCommand(queryStr, Connection);
+
+ //Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the query.
+ Connection.Close();
+
+ //Add custom logic here if needed and remove above method.
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**Update Operation:**
+
+To execute the update operation, override the `update` method of the `CustomAdaptor`. Then, integrate the following code snippet into the `CustomAdaptor` class. The below code snippet demonstrated how to handle the updating of existing records within the `update` method of the `CustomAdaptor`. Modify the logic within this method according to the requirements of your application.
+
+{% tabs %}
+{% highlight ts tabtitle="CustomAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+
+ public override update(dm: any, keyField: string, value: any): any {
+ return {
+ url: dm.dataSource.updateUrl || dm.dataSource.url,
+ data: JSON.stringify({
+ __RequestVerificationToken: "Syncfusion",
+ value: value,
+ action: 'update'
+ }),
+ type: 'POST'
+ };
+ }
+}
+
+{% endhighlight %}
+
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Update a existing data item from the data collection.
+///
+/// It contains the updated record detail which is need to be updated.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/Update")]
+public void Update([FromBody] CRUDModel value)
+{
+ //Create query to update the changes into the database by accessing its properties.
+ string queryStr = $"Update Orders set CustomerID='{value.value.CustomerID}', Freight='{value.value.Freight}',EmployeeID='{value.value.EmployeeID}',ShipCity='{value.value.ShipCity}' where OrderID='{value.value.OrderID}'";
+
+ // Establishes a connection to the SQLite database using the provided connection string.
+ SqliteConnection Connection = new SqliteConnection(ConnectionString);
+
+ // Opens the database connection to execute queries.
+ Connection.Open();
+
+ //Execute the SQLite command.
+ SqliteCommand Command = new SqliteCommand(queryStr, Connection);
+
+ //Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the query.
+ Connection.Close();
+
+ //Add custom logic here if needed and remove above method.
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**Delete Operation:**
+
+To perform the delete operation, you need to override the `remove` method of the `CustomAdaptor`. Below is the code snippet that you can add to `CustomAdaptor` class. The below code snippet demonstrated how to handle the deletion of existing records within the `remove` method of `CustomAdaptor`. Modify the logic within this method according to the requirements of your application.
+
+{% tabs %}
+{% highlight ts tabtitle="CustomAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+
+ public override remove(dm: any, keyField: string, value: any): any {
+ return {
+ url: dm.dataSource.removeUrl || dm.dataSource.url,
+ data: JSON.stringify({
+ __RequestVerificationToken: "Syncfusion",
+ key: value,
+ keyColumn: keyField,
+ action: 'remove'
+ }),
+ type: 'POST'
+ };
+ }
+}
+
+{% endhighlight %}
+
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Remove a specific data item from the data collection.
+///
+/// It contains the specific record detail which is need to be removed.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/Remove")]
+public void Remove([FromBody] CRUDModel value)
+{
+ //Create query to remove the specific from database by passing the primary key column value.
+ string queryStr = $"Delete from Orders where OrderID={value.key}";
+
+ // Establishes a connection to the SQLite database using the provided connection string.
+ SqliteConnection Connection = new SqliteConnection(ConnectionString);
+
+ // Opens the database connection to execute queries.
+ Connection.Open();
+
+ //Execute the SQLite command.
+ SqliteCommand Command = new SqliteCommand(queryStr, Connection);
+
+ //Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the query.
+ Connection.Close();
+
+ //Add custom logic here if needed and remove above method.
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+**Batch Operation:**
+
+To perform the batch operation, override the **batchRequest** method of the `CustomAdaptor` and add the following code in the `CustomAdaptor`. The below code snippet demonstrated how to handle the batch update request within the **batchRequest** method of `CustomAdaptor`. Modify the logic within this method according to the requirements of your application.
+
+{% tabs %}
+{% highlight ts tabtitle="CustomAdaptor.ts" %}
+
+import { UrlAdaptor } from '@syncfusion/ej2-data';
+
+export class CustomAdaptor extends UrlAdaptor {
+ public override processResponse(): any {
+ // Calling base class processResponse function.
+ const original: any = super.processResponse.apply(this, arguments as any);
+ return original;
+ }
+
+ public override batchRequest(dm:any, changes: any, e:any, query: any, original?: Object): Object {
+ return {
+ url: dm.dataSource.batchUrl || dm.dataSource.url,
+ data: JSON.stringify({
+ __RequestVerificationToken: "Syncfusion",
+ added: changes.addedRecords,
+ changed: changes.changedRecords,
+ deleted: changes.deletedRecords,
+ key: e.key,
+ action: 'batch'
+ }),
+ type: 'POST'
+ };
+ }
+}
+
+{% endhighlight %}
+
+{% highlight cs tabtitle="GridController.cs" %}
+
+///
+/// Batch update (Insert, Update, and Delete) a collection of data items from the data collection.
+///
+/// The set of information along with details about the CRUD actions to be executed from the database.
+/// Returns void.
+[HttpPost]
+[Route("api/[controller]/BatchUpdate")]
+public IActionResult BatchUpdate([FromBody] CRUDModel value)
+{
+ if (value.changed != null && value.changed.Count > 0)
+ {
+ foreach (Orders Record in (IEnumerable)value.changed)
+ {
+ //Create query to update the changes into the database by accessing its properties.
+ string queryStr = $"Update Orders set CustomerID='{Record.CustomerID}', Freight='{Record.Freight}',EmployeeID='{Record.EmployeeID}',ShipCity='{Record.ShipCity}' where OrderID='{Record.OrderID}'";
+
+ // Establishes a connection to the SQLite database using the provided connection string.
+ SqliteConnection Connection = new SqliteConnection(ConnectionString);
+
+ // Opens the database connection to execute queries.
+ Connection.Open();
+
+ //Execute the SQLite command.
+ SqliteCommand Command = new SqliteCommand(queryStr, Connection);
+
+ //Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the query.
+ Connection.Close();
+
+ //Add custom logic here if needed and remove above method.
+ }
+ }
+ if (value.added != null && value.added.Count > 0)
+ {
+ foreach (Orders Record in (IEnumerable)value.added)
+ {
+ //Create query to insert the specific into the database by accessing its properties.
+ string queryStr = $"Insert into Orders(CustomerID,Freight,ShipCity,EmployeeID) values('{Record.CustomerID}','{Record.Freight}','{Record.ShipCity}','{Record.EmployeeID}')";
+
+ // Establishes a connection to the SQLite database using the provided connection string.
+ SqliteConnection Connection = new SqliteConnection(ConnectionString);
+
+ // Opens the database connection to execute queries.
+ Connection.Open();
+
+ //Execute the SQLite command.
+ SqliteCommand Command = new SqliteCommand(queryStr, Connection);
+
+ //Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the query.
+ Connection.Close();
+
+ //Add custom logic here if needed and remove above method.
+ }
+ }
+ if (value.deleted != null && value.deleted.Count > 0)
+ {
+ foreach (Orders Record in (IEnumerable)value.deleted)
+ {
+ //Create query to remove the specific from database by passing the primary key column value.
+ string queryStr = $"Delete from Orders where OrderID={Record.OrderID}";
+
+ // Establishes a connection to the SQLite database using the provided connection string.
+ SqliteConnection Connection = new SqliteConnection(ConnectionString);
+
+ // Opens the database connection to execute queries.
+ Connection.Open();
+
+ //Execute the SQLite command.
+ SqliteCommand Command = new SqliteCommand(queryStr, Connection);
+
+ //Execute this code to reflect the changes into the database.
+ Command.ExecuteNonQuery();
+
+ // Close the database connection after executing the query.
+ Connection.Close();
+
+ //Add custom logic here if needed and remove above method.
+ }
+ }
+ return new JsonResult(value);
+}
+
+public class CRUDModel 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? added { get; set; }
+ public List? changed { get; set; }
+ public List? deleted { get; set; }
+ public IDictionary? @params { get; set; }
+}
+
+{% endhighlight %}
+{% endtabs %}
+
+
+
+> Please find the sample in this [GitHub location](https://github.com/SyncfusionExamples/connecting-databases-to-angular-grid/tree/master/Binding%20SQLite%20using%20CustomAdaptor/Grid_SQLite).
\ No newline at end of file
diff --git a/ej2-angular/grid/data-binding/local-data.md b/ej2-angular/grid/data-binding/local-data.md
index c7e090d27c..0ea371596b 100644
--- a/ej2-angular/grid/data-binding/local-data.md
+++ b/ej2-angular/grid/data-binding/local-data.md
@@ -390,6 +390,8 @@ The following screenshot represents the addition, editing, and deletion operatio

+> You can find a complete sample for signalR on [GitHub](https://github.com/SyncfusionExamples/Binding-data-with-SignalR-in-ej2-angular-grid).
+
## Binding data from excel file
The Syncfusion Grid component allows you to import data from Excel files into your web application for display and manipulation within the grid. This feature streamlines the process of transferring Excel data to a web-based environment. This can be achieved by using [Uploader](https://ej2.syncfusion.com/angular/documentation/uploader/getting-started) component [change](https://ej2.syncfusion.com/angular/documentation/api/uploader#change) event.
@@ -680,6 +682,8 @@ The following screenshot represents loading data when the button is clicked and

+> You can find a complete sample for Fetch request on [GitHub](https://github.com/SyncfusionExamples/Binding-data-and-perform-action-in-ej2-angular-grid-using-Fetch-request).
+
### Display the loading indicator with local data.
The Syncfusion Grid allows you to display a loading indicator while loading local data. This feature is useful when there is a delay in loading data from a local source, and you want to inform the you that the data is being fetched.
@@ -996,6 +1000,8 @@ The following screenshot represents loading data when the button is clicked and

+> You can find a complete sample for AJAX request on [GitHub](https://github.com/SyncfusionExamples/Binding-data-and-perform-action-in-ej2-angular-grid-using-Ajax-request).
+
### Display the loading indicator using AJAX.
The Syncfusion Grid allows you to display a loading indicator while loading data using AJAX. This feature is useful when there is a delay in loading data from data , and you want to inform the you that the data is being fetched. This is particularly beneficial when working with large datasets or under conditions of slower internet connections.
diff --git a/ej2-angular/rich-text-editor/editor-types/iframe.md b/ej2-angular/rich-text-editor/editor-types/iframe.md
index 9e87e12752..f3067fb34f 100644
--- a/ej2-angular/rich-text-editor/editor-types/iframe.md
+++ b/ej2-angular/rich-text-editor/editor-types/iframe.md
@@ -66,6 +66,26 @@ Likewise, add the external script file to the `< iframe >` element using the [`s
> You can also explore our [iframe in Angular Rich Text Editor example](https://ej2.syncfusion.com/angular/demos/#/material/rich-text-editor/iframe) that shows how to render the iframe in Angular Rich Text Editor.
+## Integrating Mention with Iframe
+
+Rich Text Editor supports advanced features such as Mention component, even when it is rendered inside an iframe. To enable mention functionality within the iframe-mode Rich Text Editor, you need to correctly set the [target](https://helpej2.syncfusion.com/angular/documentation/api/mention#target) of the Mention component.
+
+Specifically, assign the `inputElement` of the Rich Text Editor to the target property of the Mention component. This ensures that the Mention popup is triggered correctly when the user types a designated character (such as @) inside the Rich Text Editor's editable area.
+
+Here's an example of how to integrate Mention with Iframe editor,
+
+{% tabs %}
+{% highlight ts tabtitle="app.component.ts" %}
+{% include code-snippet/rich-text-editor/mention-iframe/src/app.component.ts %}
+{% endhighlight %}
+
+{% highlight ts tabtitle="main.ts" %}
+{% include code-snippet/rich-text-editor/mention-iframe/src/main.ts %}
+{% endhighlight %}
+{% endtabs %}
+
+{% previewsample "page.domainurl/samples/rich-text-editor/mention-iframe" %}
+
## See also
* [Implementing Inline Editing](https://ej2.syncfusion.com/angular/documentation/rich-text-editor/inline-editing)
diff --git a/ej2-angular/rich-text-editor/insert-image-media/insert-images.md b/ej2-angular/rich-text-editor/insert-image-media/insert-images.md
index 057acdf0fc..bb5cea0b27 100644
--- a/ej2-angular/rich-text-editor/insert-image-media/insert-images.md
+++ b/ej2-angular/rich-text-editor/insert-image-media/insert-images.md
@@ -326,7 +326,7 @@ You can allow the specific images alone to be uploaded using the the allowedType
``` typescript
insertImageSettings: {
- allowedTypes: ['.jpg']
+ allowedTypes: ['.jpg', '.png', '.jpeg']
}
```
diff --git a/ej2-angular/rich-text-editor/tools/styling-tools.md b/ej2-angular/rich-text-editor/tools/styling-tools.md
index 0fb99ac025..058092473f 100644
--- a/ej2-angular/rich-text-editor/tools/styling-tools.md
+++ b/ej2-angular/rich-text-editor/tools/styling-tools.md
@@ -160,6 +160,10 @@ The Rich Text Editor offers custom font and background colors along with the exi
Both the `FontColor` and `BackgroundColor` properties offer two modes: `Picker` and `Palette`. The Palette mode provides a predefined set of colors, while the Picker mode includes a color scheme to choose custom colors. You can switch between these options using the [`modeSwitcher`](https://ej2.syncfusion.com/angular/documentation/api/rich-text-editor/fontColorModel/#modeswitcher) feature.
+We can specify the number of columns in the color palette for both `FontColor` and `BackgroundColor` using the [columns](https://helpej2.syncfusion.com/angular/documentation/api/rich-text-editor/backgroundColorModel/#columns) property.
+
+The [default](https://helpej2.syncfusion.com/angular/documentation/api/rich-text-editor/backgroundColorModel/#default) property specifies the default `FontColor` and `BackgroundColor` that is applied when no color is explicitly selected by the user. This color will be preselected in the `FontColor` and `BackgroundColor` color palettes and used as the initial highlight color for text.
+
{% tabs %}
{% highlight ts tabtitle="app.component.ts" %}
{% include code-snippet/rich-text-editor/getting-started-cs26/src/app.component.ts %}
diff --git a/ej2-angular/samples/rich-text-editor/getting-started-cs26/index.html b/ej2-angular/samples/rich-text-editor/getting-started-cs26/index.html
index 833eda29fa..8f7cec3f69 100644
--- a/ej2-angular/samples/rich-text-editor/getting-started-cs26/index.html
+++ b/ej2-angular/samples/rich-text-editor/getting-started-cs26/index.html
@@ -123,10 +123,10 @@
}
}
-