Custom Binding in React Grid component
7 Sep 202624 minutes to read
The custom binding feature in the Data Grid enables managing a custom API for handling data processing externally and then binding the resulting data to the Grid. When using custom binding, the Data Grid expects the result to be an object with result (array of records to display) and count (total number of records) properties.
The Data Grid component offers a range of powerful features such as paging, grouping, sorting, and filtering. These actions trigger the dataStateChange event. CRUD actions such as Create, Read, Update, and Delete trigger the dataSourceChanged event. These events provide an opportunity to manage and manipulate data according to user interactions.
Using the dataStateChange event
The dataStateChange event triggers whenever actions modify the grid’s data state, such as changing pages, applying sorting, or grouping. This event provides detailed information about the performed action and current grid state, including parameters like page number, sorting details, and filtering criteria.
To implement the dataStateChange event effectively:
-
Subscribe to the event: In the component code, subscribe to the
dataStateChangeevent using the appropriate event handler function. This function is executed whenever the grid is interacted with. -
Handle data state: Inside the event handler function, the event arguments can be accessed to determine the specific actions and intentions. The action property of the event arguments indicates the type of action performed (e.g., paging, sorting, grouping).
The
dataStateChangeevent is not triggered during the initial rendering of the Grid. To load and display records when the Grid is first initialized, perform the data operation inside theuseEffecthook.
Perform data operations and CRUD
The Data Grid supports data operations such as filtering, sorting, grouping, searching, and CRUD actions for efficient data management.
Handling filtering
When filtering operation is performed in the grid, the dataStateChange event is triggered, providing access to the following referenced arguments within the event.

The filter action’s updated data state can be applied as shown below:
const applyFiltering = (query: Query, filter: any) => {
if (filter.columns && filter.columns.length) {
for (let i = 0; i < filter.columns.length; i++) {
const field = filter.columns[i].field;
const operator = filter.columns[i].operator;
const value = filter.columns[i].value;
query.where(field, operator, value);
}
}
else {
for (let i = 0; i < filter.length; i++) {
const { fn, e } = filter[i];
if (fn === 'onWhere') {
query.where(e as string);
}
}
}
}
/** GET all data from the server */
const reducer = (state = initialState, action) => {
createLazyLoadData();
const dataSource = [...initialState.data];
const query = new Query();
switch (action.type) {
case Grid_FetchData: {
if (action.payload.where) {
applyFiltering(query, action.gridQuery.queries);
// To get the count of the data
query.isCountRequired = true;
// Execute local data operations using the provided query
const currentResult = new DataManager(dataSource).executeLocal(query);
// Return the result along with the count of total records
return ({
data: {
result: currentResult.result, // Result of the data
count: currentResult.count // Total record count
}
})
}
}
}
}
When filtering multiple values, the predicates are provided as arguments in the dataStateChange event. Custom predicate execution can then be implemented based on the predicate values.
Handling searching
When performing a search operation in the grid, the dataStateChange event is triggered, allowing access to the following referenced arguments within the event

The grid’s data state during a search action can be updated using the following approach:
const applySearching = (query: Query, search: any) => {
// Check if a search operation is requested
if (search && search.length > 0) {
// Extract the search key and fields from the search array
const { fields, key } = search[0];
// perform search operation using the field and key on the query
query.search(key, fields);
}
}
/** GET all data from the server */
const reducer = (state = initialState, action: any) => {
createLazyLoadData();
const dataSource = [...initialState.data];
const query = new Query();
switch (action.type) {
case Grid_FetchData: {
if (!isNullOrUndefined(action.payload.search)) {
applySearching(query, action.payload.search);
}
// To get the count of the data
query.isCountRequired = true;
// Execute local data operations using the provided query
const currentResult = new DataManager(dataSource).executeLocal(query);
// Return the result along with the count of total records
return ({
data: {
result: currentResult.result, // Result of the data
count: currentResult.count // Total record count
}
})
}
}
}Handling sorting
When a sorting operation is performed in the grid, the dataStateChange event is triggered. Within this event, the following referenced arguments can be accessed.

When performing multi‑column sorting, the following referenced arguments are available in the dataStateChange event

The grid’s data state during a sort action can be updated using the following approach:
const applySorting = (query: Query, sorted: sortInfo[]) => {
if (sorted && sorted.length > 0) {
sorted.forEach(sort => {
const sortField = sort.name || sort.field;
query.sortBy(sortField as string, sort.direction);
});
}
}
/** GET all data from the server */
const reducer = (state = initialState, action) => {
createLazyLoadData();
const dataSource = [...initialState.data];
const query = new Query();
switch (action.type) {
case Grid_FetchData: {
if (!isNullOrUndefined(action.payload.sorted)) {
applySorting(query, action.payload.sorted);
}
// To get the count of the data
query.isCountRequired = true;
// Execute local data operations using the provided query
const currentResult = new DataManager(dataSource).executeLocal(query);
// Return the result along with the count of total records
return ({
data: {
result: currentResult.result, // Result of the data
count: currentResult.count // Total record count
}
})
}
}
}Handling paging
When a paging operation is performed in the grid, the dataStateChange event is triggered, and the following referenced arguments become available within this event.

The grid’s data state for a paging action can then be updated using the following approach:
const applyPaging = (query, page) => {
// Check if both 'take' and 'skip' values are available
if (page.take && page.skip) {
// Calculate pageSkip and pageTake values to get pageIndex and pageSize
const pageSkip = page.skip / page.take + 1;
const pageTake = page.take;
query.page(pageSkip, pageTake);
}
// If if only 'take' is available and 'skip' is 0, apply paging for the first page.
else if (page.skip === 0 && page.take) {
query.page(1, page.take);
}
}
/** GET all data from the server */
const reducer = (state = initialState, action) => {
createLazyLoadData();
const dataSource = [...initialState.data];
const query = new Query();
switch (action.type) {
case Grid_FetchData: {
applyPaging(query, action.payload);
// To get the count of the data
query.isCountRequired = true;
// Execute local data operations using the provided query
const currentResult = new DataManager(dataSource).executeLocal(query);
// Return the result along with the count of total records
return ({
data: {
result: currentResult.result, // Result of the data
count: currentResult.count // Total record count
}
})
}
}
}Handling grouping
When grouping operation is performed in the grid, the dataStateChange event is triggered, providing access to the following referenced arguments within the event.

The grid’s data state during a group action can be updated using the following approach:
const applyGrouping = (query: Query, group: Object[]) => {
// Check if grouping data is available
if (group && group.length > 0) {
for (let i = 0; i < group.length; i++) {
// perform group operation using the column on the query
query.group(group[i] as string);
}
}
}
/** GET all data from the server */
const reducer = (state = initialState, action) => {
createLazyLoadData();
const dataSource = [...initialState.data];
const query = new Query();
switch (action.type) {
case Grid_FetchData: {
if (!isNullOrUndefined(action.payload.group)) {
applyGrouping(query, action.payload.group);
}
// To get the count of the data
query.isCountRequired = true;
// Execute local data operations using the provided query
const currentResult = new DataManager(dataSource).executeLocal(query);
// Return the result along with the count of total records
return ({
data: {
result: currentResult.result, // Result of the data
count: currentResult.count // Total record count
}
})
}
}
}To utilize group actions, it is necessary to manage the sorting query within the service.
Lazy load grouping
In React, lazy loading refers to the technique of loading data dynamically when they are needed, instead of loading everything upfront. Lazy load grouping enables efficient loading and display of grouped data by fetching only the required data on demand.
To enable this feature, the groupSettings.enableLazyLoading property must be set to true. In addition, the state must be managed based on the initial grid action as follows.
const groupOptions = { columns: ['ProductName'], enableLazyLoading: true };
const state = { skip:0, take: 12, group: groupOptions};Based on the initial state, the relevant arguments can be accessed as illustrated below:

The grid’s state can be modified using the following approach:
const applyGrouping = (query: Query, group: Object[]) => {
// Check if grouping data is available
if (group && group.length > 0) {
for (let i = 0; i < group.length; i++) {
// perform group operation using the column on the query
query.group(group[i] as string);
}
}
}
const applyLazyLoad = (query: Query, payload: payloadInfo) => {
// Configure lazy loading for the main data
if (payload.isLazyLoad) {
query.lazyLoad.push({ key: 'isLazyLoad', value: true });
// If on-demand group loading is enabled, configure lazy loading for grouped data
if (payload.onDemandGroupInfo) {
query.lazyLoad.push({
key: 'onDemandGroupInfo',
value: payload.action.lazyLoadQuery,
});
}
}
}
/** GET all data from the server */
const reducer = (state = initialState, action) => {
createLazyLoadData();
const dataSource = [...initialState.data];
const query = new Query();
switch (action.type) {
case Grid_FetchData: {
// grouping
if (!isNullOrUndefined(action.payload.group)) {
applyGrouping(query, action.payload.group);
}
// lazy load goruping
applyLazyLoad(query, action.payload);
// To get the count of the data
query.isCountRequired = true;
// Execute local data operations using the provided query
const currentResult = new DataManager(dataSource).executeLocal(query);
// Return the result along with the count of total records
return ({
data: {
result: currentResult.result, // Result of the data
count: currentResult.count // Total record count
}
})
}
}
}Further information can be accessed in the respective documentation for lazy load grouping.
The complete example is available in the handling CRUD operations topic.
Handling CRUD
The Grid component provides powerful options for dynamically inserting, deleting, and updating records, enabling data to be modified directly within the grid. This feature is useful for performing CRUD (Create, Read, Update, Delete) operations seamlessly.
Integrating CRUD Operations
To implement CRUD operations using Syncfusion® React Grid, follow these steps:
-
Configure grid settings: Set up the grid to allow editing, adding, and deleting operations, and specify the toolbar options that will provide access to these features.
-
Handle data state changes: Utilize the dataStateChange event to respond to changes in the grid’s data state. This event is triggered whenever the grid is interacted with, such as during paging or sorting.
-
Execute CRUD operations: Within the event handler for dataSourceChanged, implement logic to handle various CRUD actions based on the action or requestType property of the event arguments.
-
Call endEdit method: After performing CRUD operations (adding, editing, or deleting), call the endEdit method to signal the completion of the operation and update the grid accordingly.
Insert operation
When an insert operation is performed in the grid, the dataSourceChanged event will be triggered, allowing access to the following referenced arguments within the event.

const reducer = (state = initialState, action) => {
createLazyLoadData();
const dataSource = [...initialState.data];
const query = new Query();
switch (action.type) {
case Grid_Add: {
// Perform add operation
gridData.insert(action.payload.data, '', undefined, 0);
const addedData = gridData.executeLocal(new Query());
initialState.data = [...addedData];
const count = addedData.length;
const result = new DataManager(addedData).executeLocal(action.gridQuery);
const currentPageData = new DataManager(result).executeLocal(new Query().skip(action.payload.state.skip).take(action.payload.state.take));
return ({
data: { result: currentPageData, count: filter.length ? result.length : count },
})
}
}
}Edit operation
When an edit operation is performed in the grid, the dataSourceChanged event will be triggered, providing access to the following referenced arguments within the event.

const reducer = (state = initialState, action) => {
createLazyLoadData();
const dataSource = [...initialState.data];
const query = new Query();
switch (action.type) {
case Grid_Editing: {
// Perform edit operation
gridData.update('OrderID', action.payload.data);
const updatedData = gridData.executeLocal(new Query());
initialState.data = [...updatedData];
const count = updatedData.length;
const result = new DataManager(updatedData).executeLocal(action.gridQuery);
const currentPageData = new DataManager(result).executeLocal(new Query().skip(action.payload.state.skip).take(action.payload.state.take));
return ({
data: { result: currentPageData, count: filter.length ? result.length : count }
})
}
}
}Delete operation
When a delete operation is performed in the grid, the dataSourceChanged event will be triggered, allowing access to the following referenced arguments within the event.

const reducer = (state = initialState, action) => {
createLazyLoadData();
const dataSource = [...initialState.data];
const query = new Query();
switch (action.type) {
case Grid_Delete: {
// Perform delete operation
gridData.remove('OrderID', { OrderID: action.payload.data[0]['OrderID'] });
const updatedData = gridData.executeLocal(new Query());
initialState.data = [...updatedData];
const count = updatedData.length;
const result = new DataManager(updatedData).executeLocal(action.gridQuery);
const currentPageData = new DataManager(result).executeLocal(new Query().skip(action.payload.state.skip).take(action.payload.state.take));
return ({
data: { result: currentPageData, count: filter.length ? result.length : count }
})
}
}
}The steps below to create a Redux service.
Step 1 : Install Dependencies
In the terminal, navigate to the project directory and run the following command to install the required packages:
npm install --save redux react-reduxThe above command install the redux package, which is the core Redux library, and the react-redux package, which provides integration between Redux and React.
Step 2 : Set Up Redux Store
Once the dependencies are installed, a Redux store must be set up in the application. Add the following code to the store.tsx file.
-
Create a new file called
store.tsxin the project’s directory. -
In the store.tsx file, import the necessary Redux functions and create the store:
import { createStore } from 'redux'; import reducer from "../reducer"; const store = createStore(reducer); export default store;In this code, the
createStorefunction is imported from the redux package along with thereducerfrom the appropriate file. The Reduxstoreis then created using thecreateStorefunction, with thereducerpassed as an argument. -
The Redux store is now set up. It can be further customized by adding middleware, enhancers, or other configurations as needed.
Step 3 : Connect Redux Provider
To make the Redux store available to the React components, the application must be wrapped with the Redux Provider component. This component receives the Redux store as a prop and connects all components within its hierarchy. Follow the steps below to connect the Redux Provider:
-
Open the root component file (usually index.ts).
-
Import the necessary dependencies:
import React from 'react'; import ReactDOM from 'react-dom/client'; import { Provider } from 'react-redux'; import store from './store'; -
Wrap the application component with the
Providercomponent and pass the Reduxstoreas a prop:ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root'));
Step 4: Create a Actions
According to Redux documentation, the Redux actions are plain JavaScript objects that describe changes to be made to the application’s state. These actions are dispatched to the Redux store, and reducers handle them to update the state accordingly.
The action type defines the name of the action that will be performed from the application. Each action type is a string that describes the specific operation being executed.
The following example demonstrates a Redux action definition for a sort operation. This code can be added to the action.tsx file:
export const Grid_FetchData = "Grid_FetchData";
export const fetchData = (state: any, query: Query) => ({
type: "Grid_FetchData",
payload: state,
gridQuery: query
});Step 5: Create a Reducer
According to the Redux documentation, the Redux reducers are functions responsible for handling actions and updating the state of the application. Reducers specify the way the state should change in response to different actions dispatched to the Redux store.
Here is an example of a Redux reducer definition for sorting operations. The reducer code can be added to the reducer.tsx file.
const initialState = {
data: lazyLoadData,
error: false,
result: [],
count: 0,
allowPaging: true
}
const applyPaging = (query, page) => {
if (page.take && page.skip) {
const pageSkip = page.skip / page.take + 1;
const pageTake = page.take;
query.page(pageSkip, pageTake);
}
else if (page.skip === 0 && page.take) {
query.page(1, page.take);
}
}
const reducer = (state = initialState, action) => {
createLazyLoadData();
const dataSource = [...initialState.data];
const query = new Query();
switch (action.type) {
case Grid_FetchData: {
applyPaging(query, action.payload);
if (action.payload.requiresCounts) {
query.isCountRequired = true;
}
const currentResult = new DataManager(dataSource).executeLocal(query);
return ({
data: { result: currentResult.result, count: currentResult.count }
})
}
default: {
const currentResult = new DataManager(dataSource).executeLocal(query);
return ({
data: { result: currentResult.result , count: currentResult.count}
})
}
}
}
export default reducer;The grid expects an object as result and count format.
Step 6: Create a Dispatch
According the Redux documentation, the dispatch function is a method provided by the Redux store. It is used to send actions to the store, triggering the state update process. Dispatching an action is the primary way to update the state in a Redux application.
When performing actions such as adding, updating, or deleting a row in the grid, it dispatches the corresponding actions to modify the data in the store and trigger updates to the grid component.
When the dataSourceChanged and dataStateChange event occur, the dispatch method is called according to their grid actions.
Add the following code to the App.tsx file.
const dataStateChange = (args: DataStateChangeEventArgs) => {
const query = (gridInstance as GridComponent).getDataModule().generateQuery();
dispatch(fetchData(args, query));
}
const dataSourceChanged = (args: DataSourceChangedEventArgs) => {
const query = (gridInstance as GridComponent).getDataModule().generateQuery();
if (state.requestType === 'delete') {
dispatch(deleteRow(state, query));
}
}Step 7: Fetching Grid Data using useEffect
To fetch grid data and populate the dataSource property of the grid, the useEffect hook can be used in React. The useEffect hook enables performing side effects such as fetching data after the component has rendered. The following example demonstrates fetching grid data using useEffect:
Add the following code to the App.tsx file.
useEffect(() => {
if (gridInstance) {
gridInstance.dataSource = state.data
}
},[state.data])The following example demonstrates the process of binding custom data to handle grid actions and CRUD operations.
import React, { useEffect} from 'react';
import { useDispatch, useSelector } from "react-redux";
import { ColumnDirective, ColumnsDirective, Filter, GridComponent, LazyLoadGroup, Inject, Page, Sort, Edit, Toolbar, Group } from '@syncfusion/ej2-react-grids'
import { addRow, deleteRow, fetchData, updateRow } from './reducer/action';
const App = () => {
let gridInstance;
const toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel', 'Search'];
const editSettings = {allowAdding: true, allowDeleting: true, allowEditing: true};
const groupSettings={enableLazyLoading: true, columns:['ProductName'], showGroupedColumn: true};
const filterSettings = {columns: [{field: 'CustomerName', matchCase: false, operator: 'startswith', predicate: 'and', value: 'Maria'}]}
const sortSettings = {columns: [{ field: 'ProductID', direction: 'Descending' }]}
const state = useSelector((state) => state);
const dispatch = useDispatch();
const dataStateChange = (state) => {
const query = gridInstance.getDataModule().generateQuery();
dispatch(fetchData(state, query));
}
const dataSourceChange = (state) =>{
const query = gridInstance.getDataModule().generateQuery(true);
if (state.requestType === "save") {
if (state.action === "add") {
dispatch(addRow(state, query));
} else if (state.action === "edit") {
dispatch(updateRow(state, query));
}
}
if (state.requestType === 'delete') {
dispatch(deleteRow(state, query));
}
}
useEffect(() => {
if (gridInstance) {
gridInstance.dataSource = state.data;
}
},[state.data])
return (
<GridComponent ref={grid => gridInstance = grid} allowSorting={true} allowFiltering={true}
allowPaging={true}
allowGrouping={true}
filterSettings={filterSettings}
groupSettings={groupSettings}
sortSettings={sortSettings}
toolbar={toolbar}
editSettings={editSettings}
dataStateChange={dataStateChange}
dataSourceChanged={dataSourceChange}
>
<ColumnsDirective>
<ColumnDirective field='OrderID' headerText='Order ID' textAlign="Right" width='120' isPrimaryKey={true} />
<ColumnDirective field='ProductName' headerText='Product Name' width='160' />
<ColumnDirective field='ProductID' headerText='Product ID' textAlign="Right" width='120' />
<ColumnDirective field='CustomerName' headerText='Customer Name' width='160' />
</ColumnsDirective>
<Inject services={[Page, Sort, Filter, Group, LazyLoadGroup, Edit, Toolbar]} />
</GridComponent>
)
}
export default (App);import React, { useEffect} from 'react';
import { useDispatch, useSelector } from "react-redux";
import { ColumnDirective, ColumnsDirective, Filter, GridComponent, DataStateChangeEventArgs, LazyLoadGroup, Inject, Page, Sort, Edit, Toolbar, GroupSettingsModel, Group, SortSettingsModel, FilterSettingsModel, DataSourceChangedEventArgs, ToolbarItems, EditSettingsModel } from '@syncfusion/ej2-react-grids'
import { addRow, deleteRow, fetchData, updateRow } from './reducer/action';
export interface gridState{
data:{
result:Object[];
count:number;
}
}
const App = () => {
var gridInstance: GridComponent|null;
const toolbar: ToolbarItems[] = ['Add', 'Edit', 'Delete', 'Update', 'Cancel', 'Search'];
const editSettings: EditSettingsModel = {allowAdding: true, allowDeleting: true, allowEditing: true};
const groupSettings: GroupSettingsModel={enableLazyLoading: true, columns:['ProductName'], showGroupedColumn: true};
const filterSettings:FilterSettingsModel = {columns: [{field: 'CustomerName', matchCase: false, operator: 'startswith', predicate: 'and', value: 'Maria'}]}
const sortSettings:SortSettingsModel = {columns: [{ field: 'ProductID', direction: 'Descending' }]}
const state = useSelector((state: gridState) => state);
const dispatch = useDispatch();
const dataStateChange = (state: DataStateChangeEventArgs) => {
const query = (gridInstance as GridComponent).getDataModule().generateQuery();
dispatch(fetchData(state, query));
}
const dataSourceChange = (state: DataSourceChangedEventArgs) =>{
const query = (gridInstance as GridComponent).getDataModule().generateQuery(true);
if (state.requestType === "save") {
if (state.action === "add") {
dispatch(addRow(state, query));
} else if (state.action === "edit") {
dispatch(updateRow(state, query));
}
}
if (state.requestType === 'delete') {
dispatch(deleteRow(state, query));
}
}
useEffect(() => {
if (gridInstance) {
gridInstance.dataSource = state.data;
}
},[state.data])
return (
<GridComponent ref={grid => gridInstance = grid} allowSorting={true} allowFiltering={true}
allowPaging={true}
allowGrouping={true}
filterSettings={filterSettings}
groupSettings={groupSettings}
sortSettings={sortSettings}
toolbar={toolbar}
editSettings={editSettings}
dataStateChange={dataStateChange}
dataSourceChanged={dataSourceChange}
>
<ColumnsDirective>
<ColumnDirective field='OrderID' headerText='Order ID' textAlign="Right" width='120' isPrimaryKey={true} />
<ColumnDirective field='ProductName' headerText='Product Name' width='160' />
<ColumnDirective field='ProductID' headerText='Product ID' textAlign="Right" width='120' />
<ColumnDirective field='CustomerName' headerText='Customer Name' width='160' />
</ColumnsDirective>
<Inject services={[Page, Sort, Filter, Group, LazyLoadGroup, Edit, Toolbar]} />
</GridComponent>
)
}
export default (App);import { Grid_Add, Grid_Delete, Grid_Editing, Grid_FetchData } from './action';
import { DataManager, Query } from '@syncfusion/ej2-data';
import { createLazyLoadData, lazyLoadData } from '../datasource';
import { DataStateChangeEventArgs, LazyLoadGroup } from '@syncfusion/ej2-react-grids';
import { isNullOrUndefined } from '@syncfusion/ej2-base';
const initialGrouping = { columns: ['ProductName'], enableLazyLoading: true };
const initialFiltering = { columns: [{ field: 'CustomerName', matchCase: false, operator: 'startswith', predicate: 'and', value: 'Maria' }] }
const initialSorting = { columns: [{ field: 'ProductID', direction: 'Descending' }] }
const initialPaging = { allowPaging: true };
const initialState = {
data: lazyLoadData,
error: false,
result: [],
count: 0,
}
const applyFiltering = (query, filter) => {
// Check if filter columns are specified
if (filter.columns && filter.columns.length) {
// Apply filtering for each specified column
for (let i = 0; i < filter.columns.length; i++) {
const field = filter.columns[i].field;
const operator = filter.columns[i].operator;
const value = filter.columns[i].value;
query.where(field, operator, value);
}
}
else {
// Apply filtering based on direct filter conditions
for (let i = 0; i < filter.length; i++) {
const { fn, e } = filter[i];
if (fn === 'onWhere') {
query.where(e);
}
}
}
}
const applySearching = (query, search) => {
// Check if a search operation is requested
if (search && search.length > 0) {
// Extract the search key and fields from the search array
const { fields, key } = search[0];
// perform search operation using the field and key on the query
query.search(key, fields);
}
}
const applySorting = (query, sorted) => {
// Check if sorting data is available
if (sorted && sorted.length > 0) {
// Iterate through each sorting info
sorted.forEach(sort => {
// get the sort field name either by name or field
const sortField = sort.name || sort.field;
// Perform sort operation using the query based on the field name and direction
query.sortBy(sortField, sort.direction);
});
}
}
const applyGrouping = (query, group) => {
// Check if grouping data is available
if (group && group.length > 0) {
for (let i = 0; i < group.length; i++) {
// perform group operation using the column on the query
query.group(group[i]);
}
}
}
const applyLazyLoad = (query, payload) => {
// Configure lazy loading for the main data
if (payload.isLazyLoad) {
query.lazyLoad.push({ key: 'isLazyLoad', value: true });
// If on-demand group loading is enabled, configure lazy loading for grouped data
if (payload.onDemandGroupInfo) {
query.lazyLoad.push({
key: 'onDemandGroupInfo',
value: payload.action.lazyLoadQuery,
});
}
}
}
const applyPaging = (query, page) => {
// Check if both 'take' and 'skip' values are available
if (page.take && page.skip) {
// Calculate pageSkip and pageTake values to get pageIndex and pageSize
const pageSkip = page.skip / page.take + 1;
const pageTake = page.take;
query.page(pageSkip, pageTake);
}
// If if only 'take' is available and 'skip' is 0, apply paging for the first page.
else if (page.skip === 0 && page.take) {
query.page(1, page.take);
}
}
const reducer = (state = initialState, action) => {
createLazyLoadData();
const dataSource = [...initialState.data];
const gridData = new DataManager(dataSource);
const query = new Query();
let filter = [];
if (action.gridQuery !== undefined) {
filter = action.gridQuery.queries.filter((fn) => {
return fn.fn === "onWhere"
})
}
switch (action.type) {
case Grid_FetchData: {
// filtering
if (action.payload.where) {
applyFiltering(query, action.gridQuery.queries);
}
// searching
if (!isNullOrUndefined(action.payload.search)) {
applySearching(query, action.payload.search);
}
// sorting
if (!isNullOrUndefined(action.payload.sorted)) {
applySorting(query, action.payload.sorted);
}
// grouping
if (!isNullOrUndefined(action.payload.group)) {
applyGrouping(query, action.payload.group);
}
// lazy load goruping
applyLazyLoad(query, action.payload);
// paging
applyPaging(query, action.payload);
// To get the count of the data
if (action.payload.requiresCounts) {
query.isCountRequired = true;
}
// Execute local data operations using the provided query
const currentResult = new DataManager(dataSource).executeLocal(query);
// Return the result along with the count of total records
return ({
data: {
result: currentResult.result, // Result of the data
count: currentResult.count // Total record count
}
})
}
case Grid_Add: {
// Perform add operation
gridData.insert(action.payload.data, '', undefined, 0);
const addedData = gridData.executeLocal(new Query());
initialState.data = [...addedData];
const count = addedData.length;
const result = new DataManager(addedData).executeLocal(action.gridQuery);
const currentPageData = new DataManager(result).executeLocal(new Query().skip(action.payload.state.skip).take(action.payload.state.take));
return ({
data: { result: currentPageData, count: filter.length ? result.length : count },
})
}
case Grid_Editing: {
// Perform edit operation
gridData.update('OrderID', action.payload.data);
const updatedData = gridData.executeLocal(new Query());
initialState.data = [...updatedData];
const count = updatedData.length;
const result = new DataManager(updatedData).executeLocal(action.gridQuery);
const currentPageData = new DataManager(result).executeLocal(new Query().skip(action.payload.state.skip).take(action.payload.state.take));
return ({
data: { result: currentPageData, count: filter.length ? result.length : count }
})
}
case Grid_Delete: {
// perform delete operation
gridData.remove('OrderID', { OrderID: action.payload.data[0]['OrderID'] });
const updatedData = gridData.executeLocal(new Query());
initialState.data = [...updatedData];
const count = updatedData.length;
const result = new DataManager(updatedData).executeLocal(action.gridQuery);
const currentPageData = new DataManager(result).executeLocal(new Query().skip(action.payload.state.skip).take(action.payload.state.take));
return ({
data: { result: currentPageData, count: filter.length ? result.length : count }
})
}
default: {
// initial filtering
if (initialFiltering.columns.length) {
applyFiltering(query, initialFiltering.columns);
}
// initial sorting
if (initialSorting.columns.length) {
applySorting(query, initialSorting.columns);
}
// initial grouping
if (initialGrouping.columns.length) {
applyGrouping(query, initialGrouping.columns);
}
if (initialGrouping.enableLazyLoading) {
query.lazyLoad.push({ key: 'isLazyLoad', value: true })
}
// initial paging
if (initialPaging.allowPaging) {
const pageSkip = 1;
const pageTake = 12;
query.page(pageSkip, pageTake);
}
// To get the count of the data
query.isCountRequired = true;
// Execute local data operations using the provided query
const currentResult = new DataManager(dataSource).executeLocal(query);
// Return the result along with the count of total records
return ({
data: {
result: currentResult.result, // Result of the data
count: currentResult.count // Total record count
}
})
}
}
}
export default reducer;import { Grid_Add, Grid_Delete, Grid_Editing, Grid_FetchData } from './action';
import { DataManager, Query } from '@syncfusion/ej2-data';
import { createLazyLoadData, lazyLoadData } from '../datasource';
import { DataStateChangeEventArgs, LazyLoadGroup } from '@syncfusion/ej2-react-grids';
import { isNullOrUndefined } from '@syncfusion/ej2-base';
interface sortInfo {
name?: string;
field?: string;
direction: string
}
interface payloadInfo {
isLazyLoad: boolean;
onDemandGroupInfo?: { [key: string]: number };
action: {
lazyLoadQuery: LazyLoadGroup;
};
}
const initialGrouping = { columns: ['ProductName'], enableLazyLoading: true };
const initialFiltering = { columns: [{ field: 'CustomerName', matchCase: false, operator: 'startswith', predicate: 'and', value: 'Maria' }] }
const initialSorting = { columns: [{ field: 'ProductID', direction: 'Descending' }] }
const initialPaging = { allowPaging: true };
const initialState: any = {
data: lazyLoadData,
error: false,
result: [],
count: 0,
}
const applyFiltering = (query: Query, filter: any) => {
// Check if filter columns are specified
if (filter.columns && filter.columns.length) {
// Apply filtering for each specified column
for (let i = 0; i < filter.columns.length; i++) {
const field = filter.columns[i].field;
const operator = filter.columns[i].operator;
const value = filter.columns[i].value;
query.where(field, operator, value);
}
}
else {
// Apply filtering based on direct filter conditions
for (let i = 0; i < filter.length; i++) {
const { fn, e } = filter[i];
if (fn === 'onWhere') {
query.where(e as string);
}
}
}
}
const applySearching = (query: Query, search: any) => {
// Check if a search operation is requested
if (search && search.length > 0) {
// Extract the search key and fields from the search array
const { fields, key } = search[0];
// perform search operation using the field and key on the query
query.search(key, fields);
}
}
const applySorting = (query: Query, sorted: sortInfo[]) => {
// Check if sorting data is available
if (sorted && sorted.length > 0) {
// Iterate through each sorting info
sorted.forEach(sort => {
// get the sort field name either by name or field
const sortField = sort.name || sort.field;
// Perform sort operation using the query based on the field name and direction
query.sortBy(sortField as string, sort.direction);
});
}
}
const applyGrouping = (query: Query, group: Object[]) => {
// Check if grouping data is available
if (group && group.length > 0) {
for (let i = 0; i < group.length; i++) {
// perform group operation using the column on the query
query.group(group[i] as string);
}
}
}
const applyLazyLoad = (query: Query, payload: payloadInfo) => {
// Configure lazy loading for the main data
if (payload.isLazyLoad) {
query.lazyLoad.push({ key: 'isLazyLoad', value: true });
// If on-demand group loading is enabled, configure lazy loading for grouped data
if (payload.onDemandGroupInfo) {
query.lazyLoad.push({
key: 'onDemandGroupInfo',
value: payload.action.lazyLoadQuery,
});
}
}
}
const applyPaging = (query: Query, page: DataStateChangeEventArgs) => {
// Check if both 'take' and 'skip' values are available
if (page.take && page.skip) {
// Calculate pageSkip and pageTake values to get pageIndex and pageSize
const pageSkip = page.skip / page.take + 1;
const pageTake = page.take;
query.page(pageSkip, pageTake);
}
// If if only 'take' is available and 'skip' is 0, apply paging for the first page.
else if (page.skip === 0 && page.take) {
query.page(1, page.take);
}
}
const reducer = (state = initialState, action: any) => {
createLazyLoadData();
const dataSource = [...initialState.data];
const gridData = new DataManager(dataSource);
const query = new Query();
let filter: any = [];
if (action.gridQuery !== undefined) {
filter = action.gridQuery.queries.filter((fn: any) => {
return fn.fn === "onWhere"
})
}
switch (action.type) {
case Grid_FetchData: {
// filtering
if (action.payload.where) {
applyFiltering(query, action.gridQuery.queries);
}
// searching
if (!isNullOrUndefined(action.payload.search)) {
applySearching(query, action.payload.search);
}
// sorting
if (!isNullOrUndefined(action.payload.sorted)) {
applySorting(query, action.payload.sorted);
}
// grouping
if (!isNullOrUndefined(action.payload.group)) {
applyGrouping(query, action.payload.group);
}
// lazy load goruping
applyLazyLoad(query, action.payload);
// paging
applyPaging(query, action.payload);
// To get the count of the data
if (action.payload.requiresCounts) {
query.isCountRequired = true;
}
// Execute local data operations using the provided query
const currentResult: any = new DataManager(dataSource).executeLocal(query);
// Return the result along with the count of total records
return ({
data: {
result: currentResult.result, // Result of the data
count: currentResult.count
} // Total record count
})
}
case Grid_Add: {
// Perform add operation
gridData.insert(action.payload.data, '', undefined, 0);
const addedData = gridData.executeLocal(new Query());
initialState.data = [...addedData];
const count = addedData.length;
const result = new DataManager(addedData).executeLocal(action.gridQuery);
const currentPageData = new DataManager(result).executeLocal(new Query().skip(action.payload.state.skip).take(action.payload.state.take));
return ({
data: { result: currentPageData, count: filter.length ? result.length : count },
})
}
case Grid_Editing: {
// Perform edit operation
gridData.update('OrderID', action.payload.data);
const updatedData = gridData.executeLocal(new Query());
initialState.data = [...updatedData];
const count = updatedData.length;
const result = new DataManager(updatedData).executeLocal(action.gridQuery);
const currentPageData = new DataManager(result).executeLocal(new Query().skip(action.payload.state.skip).take(action.payload.state.take));
return ({
data: { result: currentPageData, count: filter.length ? result.length : count }
})
}
case Grid_Delete: {
// Perform delete operation
gridData.remove('OrderID', { OrderID: action.payload.data[0]['OrderID'] });
const updatedData = gridData.executeLocal(new Query());
initialState.data = [...updatedData];
const count = updatedData.length;
const result = new DataManager(updatedData).executeLocal(action.gridQuery);
const currentPageData = new DataManager(result).executeLocal(new Query().skip(action.payload.state.skip).take(action.payload.state.take));
return ({
data: { result: currentPageData, count: filter.length ? result.length : count }
})
}
default: {
// initial filtering
if (initialFiltering.columns.length) {
applyFiltering(query, initialFiltering.columns);
}
// initial sorting
if (initialSorting.columns.length) {
applySorting(query, initialSorting.columns);
}
// initial grouping
if (initialGrouping.columns.length) {
applyGrouping(query, initialGrouping.columns);
}
if (initialGrouping.enableLazyLoading) {
query.lazyLoad.push({ key: 'isLazyLoad', value: true })
}
// initial paging
if (initialPaging.allowPaging) {
const pageSkip = 1;
const pageTake = 12;
query.page(pageSkip, pageTake);
}
// To get the count of the data
query.isCountRequired = true;
// Execute local data operations using the provided query
const currentResult = new DataManager(dataSource).executeLocal(query);
// Return the result along with the count of total records
return ({
data: {
result: currentResult.result, // Result of the data
count: currentResult.count // Total record count
}
})
}
}
}
export default reducer;import { Query } from "@syncfusion/ej2-data";
export const Grid_FetchData = "Grid_FetchData";
export const Grid_Add = "Grid_Add";
export const Grid_Delete = "Grid_Delete";
export const Grid_Editing = "Grid_Editing";
export const fetchData = (state, query) => ({
type: "Grid_FetchData",
payload: state,
gridQuery: query
});
export const addRow = (state, query) => ({
type: "Grid_Add",
payload: state,
gridQuery: query
});
export const deleteRow = (state, query) => ({
type: "Grid_Delete",
payload: state,
gridQuery: query
});
export const updateRow = (state, query) => ({
type: "Grid_Editing",
payload: state,
gridQuery: query
});import { Query } from "@syncfusion/ej2-data";
export const Grid_FetchData = "Grid_FetchData";
export const Grid_Add = "Grid_Add";
export const Grid_Delete = "Grid_Delete";
export const Grid_Editing = "Grid_Editing";
export const fetchData = (state: any, query: Query) => ({
type: "Grid_FetchData",
payload: state,
gridQuery: query
});
export const addRow = (state: any, query: Query) => ({
type: "Grid_Add",
payload: state,
gridQuery: query
});
export const deleteRow = (state: any, query: Query) => ({
type: "Grid_Delete",
payload: state,
gridQuery: query
});
export const updateRow = (state: any, query: Query) => ({
type: "Grid_Editing",
payload: state,
gridQuery: query
});export let lazyLoadData = [];
export function createLazyLoadData() {
if (lazyLoadData.length) {
return;
}
let customerid = ['VINET', 'TOMSP', 'HANAR', 'VICTE', 'SUPRD', 'HANAR', 'CHOPS', 'RICSU', 'WELLI', 'HILAA',
'ERNSH', 'CENTC', 'OTTIK', 'QUEDE', 'RATTC', 'ERNSH', 'FOLKO', 'BLONP', 'WARTH', 'FRANK', 'GROSR', 'WHITC', 'WARTH',
'SPLIR', 'RATTC', 'QUICK', 'VINET', 'MAGAA', 'TORTU', 'MORGK', 'BERGS', 'LEHMS', 'BERGS', 'ROMEY', 'ROMEY', 'LILAS',
'LEHMS', 'QUICK', 'QUICK', 'RICAR', 'REGGC', 'BSBEV', 'COMMI', 'QUEDE', 'TRADH', 'TORTU', 'RATTC', 'VINET', 'LILAS',
'BLONP', 'HUNGO', 'RICAR', 'MAGAA', 'WANDK', 'SUPRD', 'GODOS', 'TORTU', 'OLDWO', 'ROMEY', 'LONEP', 'ANATR', 'HUNGO',
'THEBI', 'DUMON', 'WANDK', 'QUICK', 'RATTC', 'ISLAT', 'RATTC', 'LONEP', 'ISLAT', 'TORTU', 'WARTH', 'ISLAT', 'PERIC',
'KOENE', 'SAVEA', 'KOENE', 'BOLID', 'FOLKO', 'FURIB', 'SPLIR', 'LILAS', 'BONAP', 'MEREP', 'WARTH', 'VICTE',
'HUNGO', 'PRINI', 'FRANK', 'OLDWO', 'MEREP', 'BONAP', 'SIMOB', 'FRANK', 'LEHMS', 'WHITC', 'QUICK', 'RATTC', 'FAMIA'];
let product = ['Chai', 'Chang', 'Aniseed Syrup', 'Chef Anton\'s Cajun Seasoning', 'Chef Anton\'s Gumbo Mix',
'Grandma\'s Boysenberry Spread', 'Uncle Bob\'s Organic Dried Pears', 'Northwoods Cranberry Sauce', 'Mishi Kobe Niku',
'Ikura', 'Queso Cabrales', 'Queso Manchego La Pastora', 'Konbu', 'Tofu', 'Genen Shouyu', 'Pavlova', 'Alice Mutton',
'Carnarvon Tigers', 'Teatime Chocolate Biscuits', 'Sir Rodney\'s Marmalade', 'Sir Rodney\'s Scones',
'Gustaf\'s Knäckebröd', 'Tunnbröd', 'Guaraná Fantástica', 'NuNuCa Nuß-Nougat-Creme', 'Gumbär Gummibärchen',
'Schoggi Schokolade', 'Rössle Sauerkraut', 'Thüringer Rostbratwurst', 'Nord-Ost Matjeshering', 'Gorgonzola Telino',
'Mascarpone Fabioli', 'Geitost', 'Sasquatch Ale', 'Steeleye Stout', 'Inlagd Sill',
'Gravad lax', 'Côte de Blaye', 'Chartreuse verte', 'Boston Crab Meat', 'Jack\'s New England Clam Chowder',
'Singaporean Hokkien Fried Mee', 'Ipoh Coffee', 'Gula Malacca', 'Rogede sild', 'Spegesild', 'Zaanse koeken',
'Chocolade', 'Maxilaku', 'Valkoinen suklaa', 'Manjimup Dried Apples', 'Filo Mix', 'Perth Pasties',
'Tourtière', 'Pâté chinois', 'Gnocchi di nonna Alice', 'Ravioli Angelo', 'Escargots de Bourgogne',
'Raclette Courdavault', 'Camembert Pierrot', 'Sirop d\'érable',
'Tarte au sucre', 'Vegie-spread', 'Wimmers gute Semmelknödel', 'Louisiana Fiery Hot Pepper Sauce',
'Louisiana Hot Spiced Okra', 'Laughing Lumberjack Lager', 'Scottish Longbreads',
'Gudbrandsdalsost', 'Outback Lager', 'Flotemysost', 'Mozzarella di Giovanni', 'Röd Kaviar', 'Longlife Tofu',
'Rhönbräu Klosterbier', 'Lakkalikööri', 'Original Frankfurter grüne Soße'];
let customername = ['Maria', 'Ana Trujillo', 'Antonio Moreno', 'Thomas Hardy', 'Christina Berglund',
'Hanna Moos', 'Frédérique Citeaux', 'Martín Sommer', 'Laurence Lebihan', 'Elizabeth Lincoln',
'Victoria Ashworth', 'Patricio Simpson', 'Francisco Chang', 'Yang Wang', 'Pedro Afonso', 'Elizabeth Brown',
'Sven Ottlieb', 'Janine Labrune', 'Ann Devon', 'Roland Mendel', 'Aria Cruz', 'Diego Roel',
'Martine Rancé', 'Maria Larsson', 'Peter Franken', 'Carine Schmitt', 'Paolo Accorti', 'Lino Rodriguez',
'Eduardo Saavedra', 'José Pedro Freyre', 'André Fonseca', 'Howard Snyder', 'Manuel Pereira',
'Mario Pontes', 'Carlos Hernández', 'Yoshi Latimer', 'Patricia McKenna', 'Helen Bennett', 'Philip Cramer',
'Daniel Tonini', 'Annette Roulet', 'Yoshi Tannamuri', 'John Steel', 'Renate Messner', 'Jaime Yorres',
'Carlos González', 'Felipe Izquierdo', 'Fran Wilson', 'Giovanni Rovelli', 'Catherine Dewey', 'Jean Fresnière',
'Alexander Feuer', 'Simon Crowther', 'Yvonne Moncada', 'Rene Phillips', 'Henriette Pfalzheim',
'Marie Bertrand', 'Guillermo Fernández', 'Georg Pipps', 'Isabel de Castro', 'Bernardo Batista', 'Lúcia Carvalho',
'Horst Kloss', 'Sergio Gutiérrez', 'Paula Wilson', 'Maurizio Moroni', 'Janete Limeira', 'Michael Holz',
'Alejandra Camino', 'Jonas Bergulfsen', 'Jose Pavarotti', 'Hari Kumar', 'Jytte Petersen', 'Dominique Perrier',
'Art Braunschweiger', 'Pascale Cartrain', 'Liz Nixon', 'Liu Wong', 'Karin Josephs', 'Miguel Angel Paolino',
'Anabela Domingues', 'Helvetius Nagy', 'Palle Ibsen', 'Mary Saveley', 'Paul Henriot', 'Rita Müller',
'Pirkko Koskitalo', 'Paula Parente', 'Karl Jablonski', 'Matti Karttunen', 'Zbyszek Piestrzeniewicz'];
let customeraddress = ['507 - 20th Ave. E.\r\nApt. 2A', '908 W. Capital Way', '722 Moss Bay Blvd.',
'4110 Old Redmond Rd.', '14 Garrett Hill', 'Coventry House\r\nMiner Rd.', 'Edgeham Hollow\r\nWinchester Way',
'4726 - 11th Ave. N.E.', '7 Houndstooth Rd.', '59 rue de l\'Abbaye', 'Luisenstr. 48', '908 W. Capital Way',
'722 Moss Bay Blvd.', '4110 Old Redmond Rd.', '14 Garrett Hill', 'Coventry House\r\nMiner Rd.',
'Edgeham Hollow\r\nWinchester Way',
'7 Houndstooth Rd.', '2817 Milton Dr.', 'Kirchgasse 6', 'Sierras de Granada 9993', 'Mehrheimerstr. 369',
'Rua da Panificadora, 12', '2817 Milton Dr.', 'Mehrheimerstr. 369'];
let quantityperunit = ['10 boxes x 20 bags', '24 - 12 oz bottles', '12 - 550 ml bottles',
'48 - 6 oz jars', '36 boxes', '12 - 8 oz jars', '12 - 1 lb pkgs.', '12 - 12 oz jars',
'18 - 500 g pkgs.', '12 - 200 ml jars',
'1 kg pkg.', '10 - 500 g pkgs.', '2 kg box', '40 - 100 g pkgs.', '24 - 250 ml bottles', '32 - 500 g boxes',
'20 - 1 kg tins', '16 kg pkg.', '10 boxes x 12 pieces', '30 gift boxes', '24 pkgs. x 4 pieces', '24 - 500 g pkgs.',
'12 - 250 g pkgs.',
'12 - 355 ml cans', '20 - 450 g glasses', '100 - 250 g bags'];
let orderID = 10248;
for (let i = 0; i < 20000; i++) {
lazyLoadData.push({
'OrderID': orderID + i,
'CustomerID': customerid[Math.floor(Math.random() * customerid.length)],
'CustomerName': customername[Math.floor(Math.random() * customername.length)],
'CustomerAddress': customeraddress[Math.floor(Math.random() * customeraddress.length)],
'ProductName': product[Math.floor(Math.random() * product.length)],
'ProductID': i,
'Quantity': quantityperunit[Math.floor(Math.random() * quantityperunit.length)]
});
}
}export let lazyLoadData: Object[] = [];
export function createLazyLoadData(): void {
if (lazyLoadData.length) {
return;
}
let customerid: string[] = ['VINET', 'TOMSP', 'HANAR', 'VICTE', 'SUPRD', 'HANAR', 'CHOPS', 'RICSU', 'WELLI', 'HILAA',
'ERNSH', 'CENTC', 'OTTIK', 'QUEDE', 'RATTC', 'ERNSH', 'FOLKO', 'BLONP', 'WARTH', 'FRANK', 'GROSR', 'WHITC', 'WARTH',
'SPLIR', 'RATTC', 'QUICK', 'VINET', 'MAGAA', 'TORTU', 'MORGK', 'BERGS', 'LEHMS', 'BERGS', 'ROMEY', 'ROMEY', 'LILAS',
'LEHMS', 'QUICK', 'QUICK', 'RICAR', 'REGGC', 'BSBEV', 'COMMI', 'QUEDE', 'TRADH', 'TORTU', 'RATTC', 'VINET', 'LILAS',
'BLONP', 'HUNGO', 'RICAR', 'MAGAA', 'WANDK', 'SUPRD', 'GODOS', 'TORTU', 'OLDWO', 'ROMEY', 'LONEP', 'ANATR', 'HUNGO',
'THEBI', 'DUMON', 'WANDK', 'QUICK', 'RATTC', 'ISLAT', 'RATTC', 'LONEP', 'ISLAT', 'TORTU', 'WARTH', 'ISLAT', 'PERIC',
'KOENE', 'SAVEA', 'KOENE', 'BOLID', 'FOLKO', 'FURIB', 'SPLIR', 'LILAS', 'BONAP', 'MEREP', 'WARTH', 'VICTE',
'HUNGO', 'PRINI', 'FRANK', 'OLDWO', 'MEREP', 'BONAP', 'SIMOB', 'FRANK', 'LEHMS', 'WHITC', 'QUICK', 'RATTC', 'FAMIA'];
let product: string[] = ['Chai', 'Chang', 'Aniseed Syrup', 'Chef Anton\'s Cajun Seasoning', 'Chef Anton\'s Gumbo Mix',
'Grandma\'s Boysenberry Spread', 'Uncle Bob\'s Organic Dried Pears', 'Northwoods Cranberry Sauce', 'Mishi Kobe Niku',
'Ikura', 'Queso Cabrales', 'Queso Manchego La Pastora', 'Konbu', 'Tofu', 'Genen Shouyu', 'Pavlova', 'Alice Mutton',
'Carnarvon Tigers', 'Teatime Chocolate Biscuits', 'Sir Rodney\'s Marmalade', 'Sir Rodney\'s Scones',
'Gustaf\'s Knäckebröd', 'Tunnbröd', 'Guaraná Fantástica', 'NuNuCa Nuß-Nougat-Creme', 'Gumbär Gummibärchen',
'Schoggi Schokolade', 'Rössle Sauerkraut', 'Thüringer Rostbratwurst', 'Nord-Ost Matjeshering', 'Gorgonzola Telino',
'Mascarpone Fabioli', 'Geitost', 'Sasquatch Ale', 'Steeleye Stout', 'Inlagd Sill',
'Gravad lax', 'Côte de Blaye', 'Chartreuse verte', 'Boston Crab Meat', 'Jack\'s New England Clam Chowder',
'Singaporean Hokkien Fried Mee', 'Ipoh Coffee', 'Gula Malacca', 'Rogede sild', 'Spegesild', 'Zaanse koeken',
'Chocolade', 'Maxilaku', 'Valkoinen suklaa', 'Manjimup Dried Apples', 'Filo Mix', 'Perth Pasties',
'Tourtière', 'Pâté chinois', 'Gnocchi di nonna Alice', 'Ravioli Angelo', 'Escargots de Bourgogne',
'Raclette Courdavault', 'Camembert Pierrot', 'Sirop d\'érable',
'Tarte au sucre', 'Vegie-spread', 'Wimmers gute Semmelknödel', 'Louisiana Fiery Hot Pepper Sauce',
'Louisiana Hot Spiced Okra', 'Laughing Lumberjack Lager', 'Scottish Longbreads',
'Gudbrandsdalsost', 'Outback Lager', 'Flotemysost', 'Mozzarella di Giovanni', 'Röd Kaviar', 'Longlife Tofu',
'Rhönbräu Klosterbier', 'Lakkalikööri', 'Original Frankfurter grüne Soße'];
let customername: string[] = ['Maria', 'Ana Trujillo', 'Antonio Moreno', 'Thomas Hardy', 'Christina Berglund',
'Hanna Moos', 'Frédérique Citeaux', 'Martín Sommer', 'Laurence Lebihan', 'Elizabeth Lincoln',
'Victoria Ashworth', 'Patricio Simpson', 'Francisco Chang', 'Yang Wang', 'Pedro Afonso', 'Elizabeth Brown',
'Sven Ottlieb', 'Janine Labrune', 'Ann Devon', 'Roland Mendel', 'Aria Cruz', 'Diego Roel',
'Martine Rancé', 'Maria Larsson', 'Peter Franken', 'Carine Schmitt', 'Paolo Accorti', 'Lino Rodriguez',
'Eduardo Saavedra', 'José Pedro Freyre', 'André Fonseca', 'Howard Snyder', 'Manuel Pereira',
'Mario Pontes', 'Carlos Hernández', 'Yoshi Latimer', 'Patricia McKenna', 'Helen Bennett', 'Philip Cramer',
'Daniel Tonini', 'Annette Roulet', 'Yoshi Tannamuri', 'John Steel', 'Renate Messner', 'Jaime Yorres',
'Carlos González', 'Felipe Izquierdo', 'Fran Wilson', 'Giovanni Rovelli', 'Catherine Dewey', 'Jean Fresnière',
'Alexander Feuer', 'Simon Crowther', 'Yvonne Moncada', 'Rene Phillips', 'Henriette Pfalzheim',
'Marie Bertrand', 'Guillermo Fernández', 'Georg Pipps', 'Isabel de Castro', 'Bernardo Batista', 'Lúcia Carvalho',
'Horst Kloss', 'Sergio Gutiérrez', 'Paula Wilson', 'Maurizio Moroni', 'Janete Limeira', 'Michael Holz',
'Alejandra Camino', 'Jonas Bergulfsen', 'Jose Pavarotti', 'Hari Kumar', 'Jytte Petersen', 'Dominique Perrier',
'Art Braunschweiger', 'Pascale Cartrain', 'Liz Nixon', 'Liu Wong', 'Karin Josephs', 'Miguel Angel Paolino',
'Anabela Domingues', 'Helvetius Nagy', 'Palle Ibsen', 'Mary Saveley', 'Paul Henriot', 'Rita Müller',
'Pirkko Koskitalo', 'Paula Parente', 'Karl Jablonski', 'Matti Karttunen', 'Zbyszek Piestrzeniewicz'];
let customeraddress: string[] = ['507 - 20th Ave. E.\r\nApt. 2A', '908 W. Capital Way', '722 Moss Bay Blvd.',
'4110 Old Redmond Rd.', '14 Garrett Hill', 'Coventry House\r\nMiner Rd.', 'Edgeham Hollow\r\nWinchester Way',
'4726 - 11th Ave. N.E.', '7 Houndstooth Rd.', '59 rue de l\'Abbaye', 'Luisenstr. 48', '908 W. Capital Way',
'722 Moss Bay Blvd.', '4110 Old Redmond Rd.', '14 Garrett Hill', 'Coventry House\r\nMiner Rd.',
'Edgeham Hollow\r\nWinchester Way',
'7 Houndstooth Rd.', '2817 Milton Dr.', 'Kirchgasse 6', 'Sierras de Granada 9993', 'Mehrheimerstr. 369',
'Rua da Panificadora, 12', '2817 Milton Dr.', 'Mehrheimerstr. 369'];
let quantityperunit: string[] = ['10 boxes x 20 bags', '24 - 12 oz bottles', '12 - 550 ml bottles',
'48 - 6 oz jars', '36 boxes', '12 - 8 oz jars', '12 - 1 lb pkgs.', '12 - 12 oz jars',
'18 - 500 g pkgs.', '12 - 200 ml jars',
'1 kg pkg.', '10 - 500 g pkgs.', '2 kg box', '40 - 100 g pkgs.', '24 - 250 ml bottles', '32 - 500 g boxes',
'20 - 1 kg tins', '16 kg pkg.', '10 boxes x 12 pieces', '30 gift boxes', '24 pkgs. x 4 pieces', '24 - 500 g pkgs.',
'12 - 250 g pkgs.',
'12 - 355 ml cans', '20 - 450 g glasses', '100 - 250 g bags'];
let orderID: number = 10248;
for (let i: number = 0; i < 20000; i++) {
lazyLoadData.push({
'OrderID': orderID + i,
'CustomerID': customerid[Math.floor(Math.random() * customerid.length)],
'CustomerName': customername[Math.floor(Math.random() * customername.length)],
'CustomerAddress': customeraddress[Math.floor(Math.random() * customeraddress.length)],
'ProductName': product[Math.floor(Math.random() * product.length)],
'ProductID': i,
'Quantity': quantityperunit[Math.floor(Math.random() * quantityperunit.length)]
});
}
}
- While working with grid edit operation, defining the
isPrimaryKeyproperty of column is a mandatory step. In case the primary key column is not defined, the edit or delete action will take place on the first row of the grid.- Need to maintain the same instance for all grid actions.
Export all records in client side
Exporting all records with async pipe proves especially beneficial when dealing with large datasets that require export for offline analysis or sharing purposes.
By default, the Syncfusion Data Grid component exports only the records available on the current page. However, the Data Grid component allows exporting all records, including those from multiple pages, by configuring the pdfExportProperties and excelExportProperties.
To export all records, including those from multiple pages, configure the pdfExportProperties.dataSource for PDF exporting and excelExportProperties.dataSource for Excel exporting within the toolbarClick event handler. Inside this event, set the dataSource property of pdfExportProperties and excelExportProperties for PDF and Excel exporting to include all records.
Excel Exporting
To export the complete grid data to Excel, utilize the excelExportProperties.dataSource when initiating the Excel export. Use the following code snippet to export all records within the grid:
const toolbarClick = async (args: ClickEventArgs) => {
const exportState = { skip: 0, take: gridInstance.current.pageSettings.totalRecordsCount};
await dispatch(fetchData(exportState));
const updatedState = store.getState();
const exportData = updatedState.data.result;
if (args.item.text === "Excel Export") {
const excelExportProps: ExcelExportProperties = {
dataSource: exportData,
};
gridInstance.current.excelExport(excelExportProps);
}
};const toolbarClick = async (args) => {
const exportState = { skip: 0, take: gridInstance.current.pageSettings.totalRecordsCount};
await dispatch(fetchData(exportState));
const updatedState = store.getState();
const exportData = updatedState.data.result;
if (args.item.text === "Excel Export") {
const excelExportProps = {
dataSource: exportData,
};
gridInstance.current.excelExport(excelExportProps);
}
};PDF Exporting
To export the complete grid data to PDF document, utilize the pdfExportProperties.dataSource when initiating the PDF export. Use the following code snippet to export all records within the grid:
const toolbarClick = async (args: ClickEventArgs) => {
const exportState = { skip: 0, take: gridInstance.current.pageSettings.totalRecordsCount};
await dispatch(fetchData(exportState));
const updatedState = store.getState();
const exportData = updatedState.data.result;
if (args.item.text === "PDF Export") {
const pdfExportProps: PdfExportProperties = {
dataSource: exportData,
};
gridInstance.current.pdfExport(pdfExportProps);
}
};For further customization on Grid export, refer to the respective documentation for PDF exporting and Excel exporting.
The following code example shows the process of exporting all records on the client side:
import React, { useEffect, useRef, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { ColumnDirective, ColumnsDirective,GridComponent,Inject,Page,Toolbar,ExcelExport,PdfExport} from "@syncfusion/ej2-react-grids";
import { fetchData } from './reducer/action';
import store from "./reducer/store/store";
const App = () => {
const gridInstance = useRef(null);
const exportingRef = useRef(false);
const dispatch = useDispatch();
const state = useSelector((state) => state);
const [gridData, setGridData] = useState([]);
const toolbarOptions = ["ExcelExport", "PdfExport"];
const validationRule = { required: true };
const orderidRules = { required: true, number: true };
const dataStateChange = (state) => {
if (state.action?.requestType !== "refresh") {
dispatch(fetchData(state));
}
};
useEffect(() => {
if (!exportingRef.current) {
setGridData(state.data);
}
}, [state.data]);
const toolbarClick = async (args) => {
gridInstance.current.showSpinner();
exportingRef.current = true;
const exportState = {
skip: 0,
take: gridInstance.current.pageSettings.totalRecordsCount
};
await dispatch(fetchData(exportState));
const updatedState = store.getState();
const exportData = updatedState.data.result;
if (args.item.text === "Excel Export") {
const excelExportProps= {
dataSource: exportData,
};
gridInstance.current.excelExport(excelExportProps);
} else if (args.item.text === "PDF Export") {
const pdfExportProps = {
dataSource: exportData,
};
gridInstance.current.pdfExport(pdfExportProps);
}
exportingRef.current = false;
};
const exportComplete = () => {
gridInstance.current?.hideSpinner();
};
return (
<GridComponent ref={gridInstance} dataSource={gridData} allowExcelExport={true} allowPdfExport={true} allowPaging={true} toolbar={toolbarOptions} toolbarClick={toolbarClick} excelExportComplete={exportComplete} pdfExportComplete{exportComplete} dataStateChange={dataStateChange}>
<ColumnsDirective>
<ColumnDirective field="OrderID" headerText="Order ID" width="140" textAlign="Right" validationRules={orderidRules}
isPrimaryKey={true}/>
<ColumnDirective field="CustomerID" headerText="Customer Name" width="150" validationRules={validationRule}/>
<ColumnDirective field="ProductID" headerText="ProductID" width="140" format="C2" textAlign="Right"/>
<ColumnDirective field="ProductName" headerText="ProductName" width="150"/>
</ColumnsDirective>
<Inject services={[Page, Toolbar, ExcelExport, PdfExport]} />
</GridComponent>
);
};
export default App;import React, { useEffect, useRef, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { ColumnDirective, ColumnsDirective,GridComponent,Inject,Page,Toolbar,ExcelExport,PdfExport,ExcelExportProperties,PdfExportProperties, ToolbarItems, DataStateChangeEventArgs} from "@syncfusion/ej2-react-grids";
import { fetchData } from './reducer/action';
import store from "./reducer/store/store";
import { ClickEventArgs } from '@syncfusion/ej2-navigations';
const App = () => {
const gridInstance = useRef<GridComponent | null>(null);
const exportingRef = useRef(false);
const dispatch = useDispatch();
const state = useSelector((state: any) => state);
const [gridData, setGridData] = useState([]);
const toolbarOptions: ToolbarItems[] = ["ExcelExport", "PdfExport"];
const validationRule = { required: true };
const orderidRules = { required: true, number: true };
const dataStateChange = (state: DataStateChangeEventArgs) => {
if (state.action?.requestType !== "refresh") {
dispatch(fetchData(state));
}
};
useEffect(() => {
if (!exportingRef.current) {
setGridData(state.data);
}
}, [state.data]);
const toolbarClick = async (args: ClickEventArgs) => {
(gridInstance.current as GridComponent).showSpinner();
exportingRef.current = true;
const exportState = {
skip: 0,
take: (gridInstance.current as GridComponent).pageSettings.totalRecordsCount
};
await dispatch(fetchData(exportState));
const updatedState = store.getState();
const exportData = updatedState.data.result;
if (args.item.text === "Excel Export") {
const excelExportProps: ExcelExportProperties = {
dataSource: exportData,
};
(gridInstance.current as GridComponent).excelExport(excelExportProps);
} else if (args.item.text === "PDF Export") {
const pdfExportProps: PdfExportProperties = {
dataSource: exportData,
};
(gridInstance.current as GridComponent).pdfExport(pdfExportProps);
}
exportingRef.current = false;
};
const exportComplete = () => {
gridInstance.current?.hideSpinner();
};
return (
<GridComponent ref={gridInstance} dataSource={gridData} allowExcelExport={true} allowPdfExport={true} allowPaging={true} toolbar={toolbarOptions} toolbarClick={toolbarClick} excelExportComplete={exportComplete} pdfExportComplete={exportComplete} dataStateChange={dataStateChange}>
<ColumnsDirective>
<ColumnDirective field="OrderID" headerText="Order ID" width="140" textAlign="Right" validationRules={orderidRules}
isPrimaryKey={true}/>
<ColumnDirective field="CustomerID" headerText="Customer Name" width="150" validationRules={validationRule}/>
<ColumnDirective field="ProductID" headerText="ProductID" width="140" format="C2" textAlign="Right"/>
<ColumnDirective field="ProductName" headerText="ProductName" width="150"/>
</ColumnsDirective>
<Inject services={[Page, Toolbar, ExcelExport, PdfExport]} />
</GridComponent>
);
};
export default App;import { Grid_FetchData } from './action';
import { DataManager, Query } from '@syncfusion/ej2-data';
import { createLazyLoadData, lazyLoadData } from '../datasource';
const initialState = {
data: lazyLoadData,
error: false,
result: [],
count: 0,
}
const applyPaging = (query, page) => {
// Check if both 'take' and 'skip' values are available.
if (page.take && page.skip) {
// Calculate pageSkip and pageTake values to get pageIndex and pageSize.
const pageSkip = page.skip / page.take + 1;
const pageTake = page.take;
query.page(pageSkip, pageTake);
}
// If if only 'take' is available and 'skip' is 0, apply paging for the first page.
else if (page.skip === 0 && page.take) {
query.page(1, page.take);
}
}
const reducer = (state = initialState, action) => {
createLazyLoadData();
const dataSource = [...initialState.data];
const query = new Query();
switch (action.type) {
case Grid_FetchData: {
applyPaging(query, action.payload);
query.isCountRequired = true;
const currentResult= new DataManager(dataSource).executeLocal(query);
return {
...state,
data: {
result: currentResult.result,
count: currentResult.count
}
};
}
default: {
query.page(1, 12);
query.isCountRequired = true;
const currentResult = new DataManager(dataSource).executeLocal(query);
return {
...state,
data: {
result: currentResult.result,
count: currentResult.count
}
};
}
}
};
export default reducer;import { Grid_FetchData } from './action';
import { DataManager, Query } from '@syncfusion/ej2-data';
import { createLazyLoadData, lazyLoadData } from '../datasource';
import { DataStateChangeEventArgs } from '@syncfusion/ej2-react-grids';
const initialState: any = {
data: lazyLoadData,
error: false,
result: [],
count: 0,
}
const applyPaging = (query: Query, page: DataStateChangeEventArgs) => {
// Check if both 'take' and 'skip' values are available.
if (page.take && page.skip) {
// Calculate pageSkip and pageTake values to get pageIndex and pageSize.
const pageSkip = page.skip / page.take + 1;
const pageTake = page.take;
query.page(pageSkip, pageTake);
}
// If if only 'take' is available and 'skip' is 0, apply paging for the first page.
else if (page.skip === 0 && page.take) {
query.page(1, page.take);
}
}
const reducer = (state = initialState, action: any) => {
createLazyLoadData();
const dataSource = [...initialState.data];
const query = new Query();
switch (action.type) {
case Grid_FetchData: {
applyPaging(query, action.payload);
query.isCountRequired = true;
const currentResult: any = new DataManager(dataSource).executeLocal(query);
return {
...state,
data: {
result: currentResult.result,
count: (currentResult as any).count
}
};
}
default: {
query.page(1, 12);
query.isCountRequired = true;
const currentResult = new DataManager(dataSource).executeLocal(query);
return {
...state,
data: {
result: (currentResult as any).result,
count: (currentResult as any).count
}
};
}
}
};
export default reducer;export const Grid_FetchData = "Grid_FetchData";
export const fetchData = (state) => ({
type: "Grid_FetchData",
payload: state,
})export const Grid_FetchData = "Grid_FetchData";
export const fetchData = (state: any) => ({
type: "Grid_FetchData",
payload: state,
})export let lazyLoadData = [];
export function createLazyLoadData() {
if (lazyLoadData.length) {
return;
}
let customerid = ['VINET', 'TOMSP', 'HANAR', 'VICTE', 'SUPRD', 'HANAR', 'CHOPS', 'RICSU', 'WELLI', 'HILAA',
'ERNSH', 'CENTC', 'OTTIK', 'QUEDE', 'RATTC', 'ERNSH', 'FOLKO', 'BLONP', 'WARTH', 'FRANK', 'GROSR', 'WHITC', 'WARTH',
'SPLIR', 'RATTC', 'QUICK', 'VINET', 'MAGAA', 'TORTU', 'MORGK', 'BERGS', 'LEHMS', 'BERGS', 'ROMEY', 'ROMEY', 'LILAS',
'LEHMS', 'QUICK', 'QUICK', 'RICAR', 'REGGC', 'BSBEV', 'COMMI', 'QUEDE', 'TRADH', 'TORTU', 'RATTC', 'VINET', 'LILAS',
'BLONP', 'HUNGO', 'RICAR', 'MAGAA', 'WANDK', 'SUPRD', 'GODOS', 'TORTU', 'OLDWO', 'ROMEY', 'LONEP', 'ANATR', 'HUNGO',
'THEBI', 'DUMON', 'WANDK', 'QUICK', 'RATTC', 'ISLAT', 'RATTC', 'LONEP', 'ISLAT', 'TORTU', 'WARTH', 'ISLAT', 'PERIC',
'KOENE', 'SAVEA', 'KOENE', 'BOLID', 'FOLKO', 'FURIB', 'SPLIR', 'LILAS', 'BONAP', 'MEREP', 'WARTH', 'VICTE',
'HUNGO', 'PRINI', 'FRANK', 'OLDWO', 'MEREP', 'BONAP', 'SIMOB', 'FRANK', 'LEHMS', 'WHITC', 'QUICK', 'RATTC', 'FAMIA'];
let product = ['Chai', 'Chang', 'Aniseed Syrup', 'Chef Anton\'s Cajun Seasoning', 'Chef Anton\'s Gumbo Mix',
'Grandma\'s Boysenberry Spread', 'Uncle Bob\'s Organic Dried Pears', 'Northwoods Cranberry Sauce', 'Mishi Kobe Niku',
'Ikura', 'Queso Cabrales', 'Queso Manchego La Pastora', 'Konbu', 'Tofu', 'Genen Shouyu', 'Pavlova', 'Alice Mutton',
'Carnarvon Tigers', 'Teatime Chocolate Biscuits', 'Sir Rodney\'s Marmalade', 'Sir Rodney\'s Scones',
'Gustaf\'s Knäckebröd', 'Tunnbröd', 'Guaraná Fantástica', 'NuNuCa Nuß-Nougat-Creme', 'Gumbär Gummibärchen',
'Schoggi Schokolade', 'Rössle Sauerkraut', 'Thüringer Rostbratwurst', 'Nord-Ost Matjeshering', 'Gorgonzola Telino',
'Mascarpone Fabioli', 'Geitost', 'Sasquatch Ale', 'Steeleye Stout', 'Inlagd Sill',
'Gravad lax', 'Côte de Blaye', 'Chartreuse verte', 'Boston Crab Meat', 'Jack\'s New England Clam Chowder',
'Singaporean Hokkien Fried Mee', 'Ipoh Coffee', 'Gula Malacca', 'Rogede sild', 'Spegesild', 'Zaanse koeken',
'Chocolade', 'Maxilaku', 'Valkoinen suklaa', 'Manjimup Dried Apples', 'Filo Mix', 'Perth Pasties',
'Tourtière', 'Pâté chinois', 'Gnocchi di nonna Alice', 'Ravioli Angelo', 'Escargots de Bourgogne',
'Raclette Courdavault', 'Camembert Pierrot', 'Sirop d\'érable',
'Tarte au sucre', 'Vegie-spread', 'Wimmers gute Semmelknödel', 'Louisiana Fiery Hot Pepper Sauce',
'Louisiana Hot Spiced Okra', 'Laughing Lumberjack Lager', 'Scottish Longbreads',
'Gudbrandsdalsost', 'Outback Lager', 'Flotemysost', 'Mozzarella di Giovanni', 'Röd Kaviar', 'Longlife Tofu',
'Rhönbräu Klosterbier', 'Lakkalikööri', 'Original Frankfurter grüne Soße'];
let customername = ['Maria', 'Ana Trujillo', 'Antonio Moreno', 'Thomas Hardy', 'Christina Berglund',
'Hanna Moos', 'Frédérique Citeaux', 'Martín Sommer', 'Laurence Lebihan', 'Elizabeth Lincoln',
'Victoria Ashworth', 'Patricio Simpson', 'Francisco Chang', 'Yang Wang', 'Pedro Afonso', 'Elizabeth Brown',
'Sven Ottlieb', 'Janine Labrune', 'Ann Devon', 'Roland Mendel', 'Aria Cruz', 'Diego Roel',
'Martine Rancé', 'Maria Larsson', 'Peter Franken', 'Carine Schmitt', 'Paolo Accorti', 'Lino Rodriguez',
'Eduardo Saavedra', 'José Pedro Freyre', 'André Fonseca', 'Howard Snyder', 'Manuel Pereira',
'Mario Pontes', 'Carlos Hernández', 'Yoshi Latimer', 'Patricia McKenna', 'Helen Bennett', 'Philip Cramer',
'Daniel Tonini', 'Annette Roulet', 'Yoshi Tannamuri', 'John Steel', 'Renate Messner', 'Jaime Yorres',
'Carlos González', 'Felipe Izquierdo', 'Fran Wilson', 'Giovanni Rovelli', 'Catherine Dewey', 'Jean Fresnière',
'Alexander Feuer', 'Simon Crowther', 'Yvonne Moncada', 'Rene Phillips', 'Henriette Pfalzheim',
'Marie Bertrand', 'Guillermo Fernández', 'Georg Pipps', 'Isabel de Castro', 'Bernardo Batista', 'Lúcia Carvalho',
'Horst Kloss', 'Sergio Gutiérrez', 'Paula Wilson', 'Maurizio Moroni', 'Janete Limeira', 'Michael Holz',
'Alejandra Camino', 'Jonas Bergulfsen', 'Jose Pavarotti', 'Hari Kumar', 'Jytte Petersen', 'Dominique Perrier',
'Art Braunschweiger', 'Pascale Cartrain', 'Liz Nixon', 'Liu Wong', 'Karin Josephs', 'Miguel Angel Paolino',
'Anabela Domingues', 'Helvetius Nagy', 'Palle Ibsen', 'Mary Saveley', 'Paul Henriot', 'Rita Müller',
'Pirkko Koskitalo', 'Paula Parente', 'Karl Jablonski', 'Matti Karttunen', 'Zbyszek Piestrzeniewicz'];
let customeraddress = ['507 - 20th Ave. E.\r\nApt. 2A', '908 W. Capital Way', '722 Moss Bay Blvd.',
'4110 Old Redmond Rd.', '14 Garrett Hill', 'Coventry House\r\nMiner Rd.', 'Edgeham Hollow\r\nWinchester Way',
'4726 - 11th Ave. N.E.', '7 Houndstooth Rd.', '59 rue de l\'Abbaye', 'Luisenstr. 48', '908 W. Capital Way',
'722 Moss Bay Blvd.', '4110 Old Redmond Rd.', '14 Garrett Hill', 'Coventry House\r\nMiner Rd.',
'Edgeham Hollow\r\nWinchester Way',
'7 Houndstooth Rd.', '2817 Milton Dr.', 'Kirchgasse 6', 'Sierras de Granada 9993', 'Mehrheimerstr. 369',
'Rua da Panificadora, 12', '2817 Milton Dr.', 'Mehrheimerstr. 369'];
let quantityperunit = ['10 boxes x 20 bags', '24 - 12 oz bottles', '12 - 550 ml bottles',
'48 - 6 oz jars', '36 boxes', '12 - 8 oz jars', '12 - 1 lb pkgs.', '12 - 12 oz jars',
'18 - 500 g pkgs.', '12 - 200 ml jars',
'1 kg pkg.', '10 - 500 g pkgs.', '2 kg box', '40 - 100 g pkgs.', '24 - 250 ml bottles', '32 - 500 g boxes',
'20 - 1 kg tins', '16 kg pkg.', '10 boxes x 12 pieces', '30 gift boxes', '24 pkgs. x 4 pieces', '24 - 500 g pkgs.',
'12 - 250 g pkgs.',
'12 - 355 ml cans', '20 - 450 g glasses', '100 - 250 g bags'];
let orderID = 10248;
for (let i = 0; i < 20000; i++) {
lazyLoadData.push({
'OrderID': orderID + i,
'CustomerID': customerid[Math.floor(Math.random() * customerid.length)],
'CustomerName': customername[Math.floor(Math.random() * customername.length)],
'CustomerAddress': customeraddress[Math.floor(Math.random() * customeraddress.length)],
'ProductName': product[Math.floor(Math.random() * product.length)],
'ProductID': i,
'Quantity': quantityperunit[Math.floor(Math.random() * quantityperunit.length)]
});
}
}export let lazyLoadData: Object[] = [];
export function createLazyLoadData(): void {
if (lazyLoadData.length) {
return;
}
let customerid: string[] = ['VINET', 'TOMSP', 'HANAR', 'VICTE', 'SUPRD', 'HANAR', 'CHOPS', 'RICSU', 'WELLI', 'HILAA',
'ERNSH', 'CENTC', 'OTTIK', 'QUEDE', 'RATTC', 'ERNSH', 'FOLKO', 'BLONP', 'WARTH', 'FRANK', 'GROSR', 'WHITC', 'WARTH',
'SPLIR', 'RATTC', 'QUICK', 'VINET', 'MAGAA', 'TORTU', 'MORGK', 'BERGS', 'LEHMS', 'BERGS', 'ROMEY', 'ROMEY', 'LILAS',
'LEHMS', 'QUICK', 'QUICK', 'RICAR', 'REGGC', 'BSBEV', 'COMMI', 'QUEDE', 'TRADH', 'TORTU', 'RATTC', 'VINET', 'LILAS',
'BLONP', 'HUNGO', 'RICAR', 'MAGAA', 'WANDK', 'SUPRD', 'GODOS', 'TORTU', 'OLDWO', 'ROMEY', 'LONEP', 'ANATR', 'HUNGO',
'THEBI', 'DUMON', 'WANDK', 'QUICK', 'RATTC', 'ISLAT', 'RATTC', 'LONEP', 'ISLAT', 'TORTU', 'WARTH', 'ISLAT', 'PERIC',
'KOENE', 'SAVEA', 'KOENE', 'BOLID', 'FOLKO', 'FURIB', 'SPLIR', 'LILAS', 'BONAP', 'MEREP', 'WARTH', 'VICTE',
'HUNGO', 'PRINI', 'FRANK', 'OLDWO', 'MEREP', 'BONAP', 'SIMOB', 'FRANK', 'LEHMS', 'WHITC', 'QUICK', 'RATTC', 'FAMIA'];
let product: string[] = ['Chai', 'Chang', 'Aniseed Syrup', 'Chef Anton\'s Cajun Seasoning', 'Chef Anton\'s Gumbo Mix',
'Grandma\'s Boysenberry Spread', 'Uncle Bob\'s Organic Dried Pears', 'Northwoods Cranberry Sauce', 'Mishi Kobe Niku',
'Ikura', 'Queso Cabrales', 'Queso Manchego La Pastora', 'Konbu', 'Tofu', 'Genen Shouyu', 'Pavlova', 'Alice Mutton',
'Carnarvon Tigers', 'Teatime Chocolate Biscuits', 'Sir Rodney\'s Marmalade', 'Sir Rodney\'s Scones',
'Gustaf\'s Knäckebröd', 'Tunnbröd', 'Guaraná Fantástica', 'NuNuCa Nuß-Nougat-Creme', 'Gumbär Gummibärchen',
'Schoggi Schokolade', 'Rössle Sauerkraut', 'Thüringer Rostbratwurst', 'Nord-Ost Matjeshering', 'Gorgonzola Telino',
'Mascarpone Fabioli', 'Geitost', 'Sasquatch Ale', 'Steeleye Stout', 'Inlagd Sill',
'Gravad lax', 'Côte de Blaye', 'Chartreuse verte', 'Boston Crab Meat', 'Jack\'s New England Clam Chowder',
'Singaporean Hokkien Fried Mee', 'Ipoh Coffee', 'Gula Malacca', 'Rogede sild', 'Spegesild', 'Zaanse koeken',
'Chocolade', 'Maxilaku', 'Valkoinen suklaa', 'Manjimup Dried Apples', 'Filo Mix', 'Perth Pasties',
'Tourtière', 'Pâté chinois', 'Gnocchi di nonna Alice', 'Ravioli Angelo', 'Escargots de Bourgogne',
'Raclette Courdavault', 'Camembert Pierrot', 'Sirop d\'érable',
'Tarte au sucre', 'Vegie-spread', 'Wimmers gute Semmelknödel', 'Louisiana Fiery Hot Pepper Sauce',
'Louisiana Hot Spiced Okra', 'Laughing Lumberjack Lager', 'Scottish Longbreads',
'Gudbrandsdalsost', 'Outback Lager', 'Flotemysost', 'Mozzarella di Giovanni', 'Röd Kaviar', 'Longlife Tofu',
'Rhönbräu Klosterbier', 'Lakkalikööri', 'Original Frankfurter grüne Soße'];
let customername: string[] = ['Maria', 'Ana Trujillo', 'Antonio Moreno', 'Thomas Hardy', 'Christina Berglund',
'Hanna Moos', 'Frédérique Citeaux', 'Martín Sommer', 'Laurence Lebihan', 'Elizabeth Lincoln',
'Victoria Ashworth', 'Patricio Simpson', 'Francisco Chang', 'Yang Wang', 'Pedro Afonso', 'Elizabeth Brown',
'Sven Ottlieb', 'Janine Labrune', 'Ann Devon', 'Roland Mendel', 'Aria Cruz', 'Diego Roel',
'Martine Rancé', 'Maria Larsson', 'Peter Franken', 'Carine Schmitt', 'Paolo Accorti', 'Lino Rodriguez',
'Eduardo Saavedra', 'José Pedro Freyre', 'André Fonseca', 'Howard Snyder', 'Manuel Pereira',
'Mario Pontes', 'Carlos Hernández', 'Yoshi Latimer', 'Patricia McKenna', 'Helen Bennett', 'Philip Cramer',
'Daniel Tonini', 'Annette Roulet', 'Yoshi Tannamuri', 'John Steel', 'Renate Messner', 'Jaime Yorres',
'Carlos González', 'Felipe Izquierdo', 'Fran Wilson', 'Giovanni Rovelli', 'Catherine Dewey', 'Jean Fresnière',
'Alexander Feuer', 'Simon Crowther', 'Yvonne Moncada', 'Rene Phillips', 'Henriette Pfalzheim',
'Marie Bertrand', 'Guillermo Fernández', 'Georg Pipps', 'Isabel de Castro', 'Bernardo Batista', 'Lúcia Carvalho',
'Horst Kloss', 'Sergio Gutiérrez', 'Paula Wilson', 'Maurizio Moroni', 'Janete Limeira', 'Michael Holz',
'Alejandra Camino', 'Jonas Bergulfsen', 'Jose Pavarotti', 'Hari Kumar', 'Jytte Petersen', 'Dominique Perrier',
'Art Braunschweiger', 'Pascale Cartrain', 'Liz Nixon', 'Liu Wong', 'Karin Josephs', 'Miguel Angel Paolino',
'Anabela Domingues', 'Helvetius Nagy', 'Palle Ibsen', 'Mary Saveley', 'Paul Henriot', 'Rita Müller',
'Pirkko Koskitalo', 'Paula Parente', 'Karl Jablonski', 'Matti Karttunen', 'Zbyszek Piestrzeniewicz'];
let customeraddress: string[] = ['507 - 20th Ave. E.\r\nApt. 2A', '908 W. Capital Way', '722 Moss Bay Blvd.',
'4110 Old Redmond Rd.', '14 Garrett Hill', 'Coventry House\r\nMiner Rd.', 'Edgeham Hollow\r\nWinchester Way',
'4726 - 11th Ave. N.E.', '7 Houndstooth Rd.', '59 rue de l\'Abbaye', 'Luisenstr. 48', '908 W. Capital Way',
'722 Moss Bay Blvd.', '4110 Old Redmond Rd.', '14 Garrett Hill', 'Coventry House\r\nMiner Rd.',
'Edgeham Hollow\r\nWinchester Way',
'7 Houndstooth Rd.', '2817 Milton Dr.', 'Kirchgasse 6', 'Sierras de Granada 9993', 'Mehrheimerstr. 369',
'Rua da Panificadora, 12', '2817 Milton Dr.', 'Mehrheimerstr. 369'];
let quantityperunit: string[] = ['10 boxes x 20 bags', '24 - 12 oz bottles', '12 - 550 ml bottles',
'48 - 6 oz jars', '36 boxes', '12 - 8 oz jars', '12 - 1 lb pkgs.', '12 - 12 oz jars',
'18 - 500 g pkgs.', '12 - 200 ml jars',
'1 kg pkg.', '10 - 500 g pkgs.', '2 kg box', '40 - 100 g pkgs.', '24 - 250 ml bottles', '32 - 500 g boxes',
'20 - 1 kg tins', '16 kg pkg.', '10 boxes x 12 pieces', '30 gift boxes', '24 pkgs. x 4 pieces', '24 - 500 g pkgs.',
'12 - 250 g pkgs.',
'12 - 355 ml cans', '20 - 450 g glasses', '100 - 250 g bags'];
let orderID: number = 10248;
for (let i: number = 0; i < 1000; i++) {
lazyLoadData.push({
'OrderID': orderID + i,
'CustomerID': customerid[Math.floor(Math.random() * customerid.length)],
'CustomerName': customername[Math.floor(Math.random() * customername.length)],
'CustomerAddress': customeraddress[Math.floor(Math.random() * customeraddress.length)],
'ProductName': product[Math.floor(Math.random() * product.length)],
'ProductID': i,
'Quantity': quantityperunit[Math.floor(Math.random() * quantityperunit.length)]
});
}
}Sending additional parameters to the server
The Data Grid component enables inclusion of custom parameters in data requests. This feature proves particularly useful when providing additional information to the server for enhanced processing capabilities.
By utilizing the query property of the grid along with the addParams method of the Query class, custom parameters can be incorporated into data requests for every grid action.
To enable custom parameters in data requests for the grid component:
1. Bind the Query Object to the Grid: Assign the initialized query object to the query property of the Data Grid component.
2. Initialize the Query Object: Create a new instance of the Query class and use the addParams method to add the custom parameters.
3. Handle Data State Changes: To dynamically update data based on interactions, implement the dataStateChange event handler to execute the query with the updated state.
4. Execute Data Request: In the service, execute the data request by combining the custom parameters with other query parameters such as paging and sorting.
The following example demonstrates the process of sending additional parameters to the server.
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from "react-redux";
import { ColumnDirective, ColumnsDirective, GridComponent, DataStateChangeEventArgs, Inject, Page, Sort, SortSettingsModel } from '@syncfusion/ej2-react-grids'
import { fetchData } from './reducer/action';
import { Query } from '@syncfusion/ej2-data';
const App = () => {
let gridInstance;
const sortSettings = { columns: [{ field: 'ProductID', direction: 'Descending' }] }
const query = new Query().addParams('Syncfusion_React_Grid', 'true');
const state = useSelector((state) => state);
const dispatch = useDispatch();
const dataStateChange = (state) => {
dispatch(fetchData(state));
}
useEffect(() => {
if (gridInstance) {
gridInstance.dataSource = state.data;
}
}, [state.data])
return (
<GridComponent ref={grid => gridInstance = grid} query={query} allowSorting={true}
allowPaging={true}
sortSettings={sortSettings}
dataStateChange={dataStateChange}
>
<ColumnsDirective>
<ColumnDirective field='OrderID' headerText='Order ID' textAlign="Right" width='120' isPrimaryKey={true} />
<ColumnDirective field='ProductName' headerText='Product Name' width='160' />
<ColumnDirective field='ProductID' headerText='Product ID' textAlign="Right" width='120' />
<ColumnDirective field='CustomerName' headerText='Customer Name' width='160' />
</ColumnsDirective>
<Inject services={[Page, Sort]} />
</GridComponent>
)
}
export default (App);import React, { useEffect } from 'react';
import { useDispatch, useSelector } from "react-redux";
import { ColumnDirective, ColumnsDirective, GridComponent, DataStateChangeEventArgs, Inject, Page, Sort, SortSettingsModel } from '@syncfusion/ej2-react-grids'
import { fetchData } from './reducer/action';
import { Query } from '@syncfusion/ej2-data';
export interface gridState {
data: {
result: Object[];
count: number;
}
}
const App = () => {
let gridInstance: GridComponent | null;
const sortSettings: SortSettingsModel = { columns: [{ field: 'ProductID', direction: 'Descending' }] }
const query: Query = new Query().addParams('Syncfusion_React_Grid', 'true');
const state = useSelector((state: gridState) => state);
const dispatch = useDispatch();
const dataStateChange = (state: DataStateChangeEventArgs) => {
dispatch(fetchData(state));
}
useEffect(() => {
if (gridInstance) {
gridInstance.dataSource = state.data;
}
}, [state.data])
return (
<GridComponent ref={grid => gridInstance = grid} query={query} allowSorting={true}
allowPaging={true}
sortSettings={sortSettings}
dataStateChange={dataStateChange}
>
<ColumnsDirective>
<ColumnDirective field='OrderID' headerText='Order ID' textAlign="Right" width='120' isPrimaryKey={true} />
<ColumnDirective field='ProductName' headerText='Product Name' width='160' />
<ColumnDirective field='ProductID' headerText='Product ID' textAlign="Right" width='120' />
<ColumnDirective field='CustomerName' headerText='Customer Name' width='160' />
</ColumnsDirective>
<Inject services={[Page, Sort]} />
</GridComponent>
)
}
export default (App);import { Grid_FetchData } from './action';
import { DataManager, Query } from '@syncfusion/ej2-data';
import { createLazyLoadData, lazyLoadData } from '../datasource';
import { isNullOrUndefined } from '@syncfusion/ej2-base';
const initialSorting = { columns: [{ field: 'ProductID', direction: 'Descending' }] }
const initialParams = new Query().addParams('Syncfusion_React_Grid', 'true');
const initialPaging = { allowPaging: true };
const initialState = {
data: lazyLoadData,
error: false,
result: [],
count: 0,
}
const applySorting = (query, sorted) => {
if (sorted && sorted.length > 0) {
sorted.forEach(sort => {
const sortField = sort.name || sort.field;
query.sortBy(sortField, sort.direction);
});
}
}
const applyPage = (query, page) => {
if (page.take && page.skip) {
const pageSkip = page.skip / page.take + 1;
const pageTake = page.take;
query.page(pageSkip, pageTake);
}
else if (page.skip === 0 && page.take) {
query.page(1, page.take);
}
}
const reducer = (state = initialState, action) => {
createLazyLoadData();
const dataSource = [...initialState.data];
let query = new Query();
switch (action.type) {
case Grid_FetchData: {
//sorting
if (!isNullOrUndefined(action.payload.sorted)) {
applySorting(query, action.payload.sorted);
}
//paging
applyPage(query, action.payload);
//addParams
if (action.payload.params.length) {
query.addParams('Syncfusion_React_Grid', 'true');
}
if (action.payload.requiresCounts) {
query.isCountRequired = true;
}
const currentResult = new DataManager(dataSource).executeLocal(query);
return ({
data: {
result: currentResult.result,
count: currentResult.count
}
})
}
default:
if (initialSorting.columns.length) {
applySorting(query, initialSorting.columns);
}
if (initialPaging.allowPaging) {
const pageSkip = 1;
const pageTake = 12;
query.page(pageSkip, pageTake);
}
if (initialParams.params.length) {
query.addParams('Syncfusion_React_Grid', 'true');
}
query.isCountRequired = true;
const currentResult = new DataManager(dataSource).executeLocal(query);
return ({
data: { result: currentResult.result, count: currentResult.count }
})
}
}
export default reducer;import { Grid_FetchData } from './action';
import { DataManager, Query } from '@syncfusion/ej2-data';
import { createLazyLoadData, lazyLoadData } from '../datasource';
import { DataStateChangeEventArgs } from '@syncfusion/ej2-react-grids';
import { isNullOrUndefined } from '@syncfusion/ej2-base';
interface sortInfo {
name?: string;
field?: string;
direction: string
}
const initialSorting = { columns: [{ field: 'ProductID', direction: 'Descending' }] }
const initialParams = new Query().addParams('Syncfusion_React_Grid', 'true');
const initialPaging = { allowPaging: true };
const initialState: any = {
data: lazyLoadData,
error: false,
result: [],
count: 0,
}
const applySorting = (query: Query, sorted: sortInfo[]) => {
if (sorted && sorted.length > 0) {
sorted.forEach(sort => {
const sortField = sort.name || sort.field;
query.sortBy(sortField as string, sort.direction);
});
}
}
const applyPage = (query: Query, page: DataStateChangeEventArgs) => {
if (page.take && page.skip) {
const pageSkip = page.skip / page.take + 1;
const pageTake = page.take;
query.page(pageSkip, pageTake);
}
else if (page.skip === 0 && page.take) {
query.page(1, page.take);
}
}
const reducer = (state = initialState, action: any) => {
createLazyLoadData();
const dataSource = [...initialState.data];
let query = new Query();
switch (action.type) {
case Grid_FetchData: {
// sorting
if (!isNullOrUndefined(action.payload.sorted)) {
applySorting(query, action.payload.sorted);
}
// paging
applyPage(query, action.payload);
//addParams
if (action.payload.params.length) {
query.addParams('Syncfusion_React_Grid', 'true');
}
// To get the count of the data
if (action.payload.requiresCounts) {
query.isCountRequired = true;
}
const currentResult: any = new DataManager(dataSource).executeLocal(query);
return ({
data: {
result: currentResult.result,
count: currentResult.count
}
})
}
default:
if (initialSorting.columns.length) {
applySorting(query, initialSorting.columns);
}
if (initialPaging.allowPaging) {
const pageSkip = 1;
const pageTake = 12;
query.page(pageSkip, pageTake);
}
if (initialParams.params.length) {
query.addParams('Syncfusion_React_Grid', 'true');
}
query.isCountRequired = true;
const currentResult: any = new DataManager(dataSource).executeLocal(query);
return ({
data: { result: currentResult.result, count: currentResult.count }
})
}
}
export default reducer;export const Grid_FetchData = "Grid_FetchData";
export const fetchData= (state) => ({
type: "Grid_FetchData",
payload: state,
});export const Grid_FetchData = "Grid_FetchData";
export const fetchData= (state: any) => ({
type: "Grid_FetchData",
payload: state,
});export let lazyLoadData = [];
export function createLazyLoadData() {
if (lazyLoadData.length) {
return;
}
let customerid = ['VINET', 'TOMSP', 'HANAR', 'VICTE', 'SUPRD', 'HANAR', 'CHOPS', 'RICSU', 'WELLI', 'HILAA',
'ERNSH', 'CENTC', 'OTTIK', 'QUEDE', 'RATTC', 'ERNSH', 'FOLKO', 'BLONP', 'WARTH', 'FRANK', 'GROSR', 'WHITC', 'WARTH',
'SPLIR', 'RATTC', 'QUICK', 'VINET', 'MAGAA', 'TORTU', 'MORGK', 'BERGS', 'LEHMS', 'BERGS', 'ROMEY', 'ROMEY', 'LILAS',
'LEHMS', 'QUICK', 'QUICK', 'RICAR', 'REGGC', 'BSBEV', 'COMMI', 'QUEDE', 'TRADH', 'TORTU', 'RATTC', 'VINET', 'LILAS',
'BLONP', 'HUNGO', 'RICAR', 'MAGAA', 'WANDK', 'SUPRD', 'GODOS', 'TORTU', 'OLDWO', 'ROMEY', 'LONEP', 'ANATR', 'HUNGO',
'THEBI', 'DUMON', 'WANDK', 'QUICK', 'RATTC', 'ISLAT', 'RATTC', 'LONEP', 'ISLAT', 'TORTU', 'WARTH', 'ISLAT', 'PERIC',
'KOENE', 'SAVEA', 'KOENE', 'BOLID', 'FOLKO', 'FURIB', 'SPLIR', 'LILAS', 'BONAP', 'MEREP', 'WARTH', 'VICTE',
'HUNGO', 'PRINI', 'FRANK', 'OLDWO', 'MEREP', 'BONAP', 'SIMOB', 'FRANK', 'LEHMS', 'WHITC', 'QUICK', 'RATTC', 'FAMIA'];
let product = ['Chai', 'Chang', 'Aniseed Syrup', 'Chef Anton\'s Cajun Seasoning', 'Chef Anton\'s Gumbo Mix',
'Grandma\'s Boysenberry Spread', 'Uncle Bob\'s Organic Dried Pears', 'Northwoods Cranberry Sauce', 'Mishi Kobe Niku',
'Ikura', 'Queso Cabrales', 'Queso Manchego La Pastora', 'Konbu', 'Tofu', 'Genen Shouyu', 'Pavlova', 'Alice Mutton',
'Carnarvon Tigers', 'Teatime Chocolate Biscuits', 'Sir Rodney\'s Marmalade', 'Sir Rodney\'s Scones',
'Gustaf\'s Knäckebröd', 'Tunnbröd', 'Guaraná Fantástica', 'NuNuCa Nuß-Nougat-Creme', 'Gumbär Gummibärchen',
'Schoggi Schokolade', 'Rössle Sauerkraut', 'Thüringer Rostbratwurst', 'Nord-Ost Matjeshering', 'Gorgonzola Telino',
'Mascarpone Fabioli', 'Geitost', 'Sasquatch Ale', 'Steeleye Stout', 'Inlagd Sill',
'Gravad lax', 'Côte de Blaye', 'Chartreuse verte', 'Boston Crab Meat', 'Jack\'s New England Clam Chowder',
'Singaporean Hokkien Fried Mee', 'Ipoh Coffee', 'Gula Malacca', 'Rogede sild', 'Spegesild', 'Zaanse koeken',
'Chocolade', 'Maxilaku', 'Valkoinen suklaa', 'Manjimup Dried Apples', 'Filo Mix', 'Perth Pasties',
'Tourtière', 'Pâté chinois', 'Gnocchi di nonna Alice', 'Ravioli Angelo', 'Escargots de Bourgogne',
'Raclette Courdavault', 'Camembert Pierrot', 'Sirop d\'érable',
'Tarte au sucre', 'Vegie-spread', 'Wimmers gute Semmelknödel', 'Louisiana Fiery Hot Pepper Sauce',
'Louisiana Hot Spiced Okra', 'Laughing Lumberjack Lager', 'Scottish Longbreads',
'Gudbrandsdalsost', 'Outback Lager', 'Flotemysost', 'Mozzarella di Giovanni', 'Röd Kaviar', 'Longlife Tofu',
'Rhönbräu Klosterbier', 'Lakkalikööri', 'Original Frankfurter grüne Soße'];
let customername = ['Maria', 'Ana Trujillo', 'Antonio Moreno', 'Thomas Hardy', 'Christina Berglund',
'Hanna Moos', 'Frédérique Citeaux', 'Martín Sommer', 'Laurence Lebihan', 'Elizabeth Lincoln',
'Victoria Ashworth', 'Patricio Simpson', 'Francisco Chang', 'Yang Wang', 'Pedro Afonso', 'Elizabeth Brown',
'Sven Ottlieb', 'Janine Labrune', 'Ann Devon', 'Roland Mendel', 'Aria Cruz', 'Diego Roel',
'Martine Rancé', 'Maria Larsson', 'Peter Franken', 'Carine Schmitt', 'Paolo Accorti', 'Lino Rodriguez',
'Eduardo Saavedra', 'José Pedro Freyre', 'André Fonseca', 'Howard Snyder', 'Manuel Pereira',
'Mario Pontes', 'Carlos Hernández', 'Yoshi Latimer', 'Patricia McKenna', 'Helen Bennett', 'Philip Cramer',
'Daniel Tonini', 'Annette Roulet', 'Yoshi Tannamuri', 'John Steel', 'Renate Messner', 'Jaime Yorres',
'Carlos González', 'Felipe Izquierdo', 'Fran Wilson', 'Giovanni Rovelli', 'Catherine Dewey', 'Jean Fresnière',
'Alexander Feuer', 'Simon Crowther', 'Yvonne Moncada', 'Rene Phillips', 'Henriette Pfalzheim',
'Marie Bertrand', 'Guillermo Fernández', 'Georg Pipps', 'Isabel de Castro', 'Bernardo Batista', 'Lúcia Carvalho',
'Horst Kloss', 'Sergio Gutiérrez', 'Paula Wilson', 'Maurizio Moroni', 'Janete Limeira', 'Michael Holz',
'Alejandra Camino', 'Jonas Bergulfsen', 'Jose Pavarotti', 'Hari Kumar', 'Jytte Petersen', 'Dominique Perrier',
'Art Braunschweiger', 'Pascale Cartrain', 'Liz Nixon', 'Liu Wong', 'Karin Josephs', 'Miguel Angel Paolino',
'Anabela Domingues', 'Helvetius Nagy', 'Palle Ibsen', 'Mary Saveley', 'Paul Henriot', 'Rita Müller',
'Pirkko Koskitalo', 'Paula Parente', 'Karl Jablonski', 'Matti Karttunen', 'Zbyszek Piestrzeniewicz'];
let customeraddress = ['507 - 20th Ave. E.\r\nApt. 2A', '908 W. Capital Way', '722 Moss Bay Blvd.',
'4110 Old Redmond Rd.', '14 Garrett Hill', 'Coventry House\r\nMiner Rd.', 'Edgeham Hollow\r\nWinchester Way',
'4726 - 11th Ave. N.E.', '7 Houndstooth Rd.', '59 rue de l\'Abbaye', 'Luisenstr. 48', '908 W. Capital Way',
'722 Moss Bay Blvd.', '4110 Old Redmond Rd.', '14 Garrett Hill', 'Coventry House\r\nMiner Rd.',
'Edgeham Hollow\r\nWinchester Way',
'7 Houndstooth Rd.', '2817 Milton Dr.', 'Kirchgasse 6', 'Sierras de Granada 9993', 'Mehrheimerstr. 369',
'Rua da Panificadora, 12', '2817 Milton Dr.', 'Mehrheimerstr. 369'];
let quantityperunit = ['10 boxes x 20 bags', '24 - 12 oz bottles', '12 - 550 ml bottles',
'48 - 6 oz jars', '36 boxes', '12 - 8 oz jars', '12 - 1 lb pkgs.', '12 - 12 oz jars',
'18 - 500 g pkgs.', '12 - 200 ml jars',
'1 kg pkg.', '10 - 500 g pkgs.', '2 kg box', '40 - 100 g pkgs.', '24 - 250 ml bottles', '32 - 500 g boxes',
'20 - 1 kg tins', '16 kg pkg.', '10 boxes x 12 pieces', '30 gift boxes', '24 pkgs. x 4 pieces', '24 - 500 g pkgs.',
'12 - 250 g pkgs.',
'12 - 355 ml cans', '20 - 450 g glasses', '100 - 250 g bags'];
let orderID = 10248;
for (let i = 0; i < 20000; i++) {
lazyLoadData.push({
'OrderID': orderID + i,
'CustomerID': customerid[Math.floor(Math.random() * customerid.length)],
'CustomerName': customername[Math.floor(Math.random() * customername.length)],
'CustomerAddress': customeraddress[Math.floor(Math.random() * customeraddress.length)],
'ProductName': product[Math.floor(Math.random() * product.length)],
'ProductID': i,
'Quantity': quantityperunit[Math.floor(Math.random() * quantityperunit.length)]
});
}
}export let lazyLoadData: Object[] = [];
export function createLazyLoadData(): void {
if (lazyLoadData.length) {
return;
}
let customerid: string[] = ['VINET', 'TOMSP', 'HANAR', 'VICTE', 'SUPRD', 'HANAR', 'CHOPS', 'RICSU', 'WELLI', 'HILAA',
'ERNSH', 'CENTC', 'OTTIK', 'QUEDE', 'RATTC', 'ERNSH', 'FOLKO', 'BLONP', 'WARTH', 'FRANK', 'GROSR', 'WHITC', 'WARTH',
'SPLIR', 'RATTC', 'QUICK', 'VINET', 'MAGAA', 'TORTU', 'MORGK', 'BERGS', 'LEHMS', 'BERGS', 'ROMEY', 'ROMEY', 'LILAS',
'LEHMS', 'QUICK', 'QUICK', 'RICAR', 'REGGC', 'BSBEV', 'COMMI', 'QUEDE', 'TRADH', 'TORTU', 'RATTC', 'VINET', 'LILAS',
'BLONP', 'HUNGO', 'RICAR', 'MAGAA', 'WANDK', 'SUPRD', 'GODOS', 'TORTU', 'OLDWO', 'ROMEY', 'LONEP', 'ANATR', 'HUNGO',
'THEBI', 'DUMON', 'WANDK', 'QUICK', 'RATTC', 'ISLAT', 'RATTC', 'LONEP', 'ISLAT', 'TORTU', 'WARTH', 'ISLAT', 'PERIC',
'KOENE', 'SAVEA', 'KOENE', 'BOLID', 'FOLKO', 'FURIB', 'SPLIR', 'LILAS', 'BONAP', 'MEREP', 'WARTH', 'VICTE',
'HUNGO', 'PRINI', 'FRANK', 'OLDWO', 'MEREP', 'BONAP', 'SIMOB', 'FRANK', 'LEHMS', 'WHITC', 'QUICK', 'RATTC', 'FAMIA'];
let product: string[] = ['Chai', 'Chang', 'Aniseed Syrup', 'Chef Anton\'s Cajun Seasoning', 'Chef Anton\'s Gumbo Mix',
'Grandma\'s Boysenberry Spread', 'Uncle Bob\'s Organic Dried Pears', 'Northwoods Cranberry Sauce', 'Mishi Kobe Niku',
'Ikura', 'Queso Cabrales', 'Queso Manchego La Pastora', 'Konbu', 'Tofu', 'Genen Shouyu', 'Pavlova', 'Alice Mutton',
'Carnarvon Tigers', 'Teatime Chocolate Biscuits', 'Sir Rodney\'s Marmalade', 'Sir Rodney\'s Scones',
'Gustaf\'s Knäckebröd', 'Tunnbröd', 'Guaraná Fantástica', 'NuNuCa Nuß-Nougat-Creme', 'Gumbär Gummibärchen',
'Schoggi Schokolade', 'Rössle Sauerkraut', 'Thüringer Rostbratwurst', 'Nord-Ost Matjeshering', 'Gorgonzola Telino',
'Mascarpone Fabioli', 'Geitost', 'Sasquatch Ale', 'Steeleye Stout', 'Inlagd Sill',
'Gravad lax', 'Côte de Blaye', 'Chartreuse verte', 'Boston Crab Meat', 'Jack\'s New England Clam Chowder',
'Singaporean Hokkien Fried Mee', 'Ipoh Coffee', 'Gula Malacca', 'Rogede sild', 'Spegesild', 'Zaanse koeken',
'Chocolade', 'Maxilaku', 'Valkoinen suklaa', 'Manjimup Dried Apples', 'Filo Mix', 'Perth Pasties',
'Tourtière', 'Pâté chinois', 'Gnocchi di nonna Alice', 'Ravioli Angelo', 'Escargots de Bourgogne',
'Raclette Courdavault', 'Camembert Pierrot', 'Sirop d\'érable',
'Tarte au sucre', 'Vegie-spread', 'Wimmers gute Semmelknödel', 'Louisiana Fiery Hot Pepper Sauce',
'Louisiana Hot Spiced Okra', 'Laughing Lumberjack Lager', 'Scottish Longbreads',
'Gudbrandsdalsost', 'Outback Lager', 'Flotemysost', 'Mozzarella di Giovanni', 'Röd Kaviar', 'Longlife Tofu',
'Rhönbräu Klosterbier', 'Lakkalikööri', 'Original Frankfurter grüne Soße'];
let customername: string[] = ['Maria', 'Ana Trujillo', 'Antonio Moreno', 'Thomas Hardy', 'Christina Berglund',
'Hanna Moos', 'Frédérique Citeaux', 'Martín Sommer', 'Laurence Lebihan', 'Elizabeth Lincoln',
'Victoria Ashworth', 'Patricio Simpson', 'Francisco Chang', 'Yang Wang', 'Pedro Afonso', 'Elizabeth Brown',
'Sven Ottlieb', 'Janine Labrune', 'Ann Devon', 'Roland Mendel', 'Aria Cruz', 'Diego Roel',
'Martine Rancé', 'Maria Larsson', 'Peter Franken', 'Carine Schmitt', 'Paolo Accorti', 'Lino Rodriguez',
'Eduardo Saavedra', 'José Pedro Freyre', 'André Fonseca', 'Howard Snyder', 'Manuel Pereira',
'Mario Pontes', 'Carlos Hernández', 'Yoshi Latimer', 'Patricia McKenna', 'Helen Bennett', 'Philip Cramer',
'Daniel Tonini', 'Annette Roulet', 'Yoshi Tannamuri', 'John Steel', 'Renate Messner', 'Jaime Yorres',
'Carlos González', 'Felipe Izquierdo', 'Fran Wilson', 'Giovanni Rovelli', 'Catherine Dewey', 'Jean Fresnière',
'Alexander Feuer', 'Simon Crowther', 'Yvonne Moncada', 'Rene Phillips', 'Henriette Pfalzheim',
'Marie Bertrand', 'Guillermo Fernández', 'Georg Pipps', 'Isabel de Castro', 'Bernardo Batista', 'Lúcia Carvalho',
'Horst Kloss', 'Sergio Gutiérrez', 'Paula Wilson', 'Maurizio Moroni', 'Janete Limeira', 'Michael Holz',
'Alejandra Camino', 'Jonas Bergulfsen', 'Jose Pavarotti', 'Hari Kumar', 'Jytte Petersen', 'Dominique Perrier',
'Art Braunschweiger', 'Pascale Cartrain', 'Liz Nixon', 'Liu Wong', 'Karin Josephs', 'Miguel Angel Paolino',
'Anabela Domingues', 'Helvetius Nagy', 'Palle Ibsen', 'Mary Saveley', 'Paul Henriot', 'Rita Müller',
'Pirkko Koskitalo', 'Paula Parente', 'Karl Jablonski', 'Matti Karttunen', 'Zbyszek Piestrzeniewicz'];
let customeraddress: string[] = ['507 - 20th Ave. E.\r\nApt. 2A', '908 W. Capital Way', '722 Moss Bay Blvd.',
'4110 Old Redmond Rd.', '14 Garrett Hill', 'Coventry House\r\nMiner Rd.', 'Edgeham Hollow\r\nWinchester Way',
'4726 - 11th Ave. N.E.', '7 Houndstooth Rd.', '59 rue de l\'Abbaye', 'Luisenstr. 48', '908 W. Capital Way',
'722 Moss Bay Blvd.', '4110 Old Redmond Rd.', '14 Garrett Hill', 'Coventry House\r\nMiner Rd.',
'Edgeham Hollow\r\nWinchester Way',
'7 Houndstooth Rd.', '2817 Milton Dr.', 'Kirchgasse 6', 'Sierras de Granada 9993', 'Mehrheimerstr. 369',
'Rua da Panificadora, 12', '2817 Milton Dr.', 'Mehrheimerstr. 369'];
let quantityperunit: string[] = ['10 boxes x 20 bags', '24 - 12 oz bottles', '12 - 550 ml bottles',
'48 - 6 oz jars', '36 boxes', '12 - 8 oz jars', '12 - 1 lb pkgs.', '12 - 12 oz jars',
'18 - 500 g pkgs.', '12 - 200 ml jars',
'1 kg pkg.', '10 - 500 g pkgs.', '2 kg box', '40 - 100 g pkgs.', '24 - 250 ml bottles', '32 - 500 g boxes',
'20 - 1 kg tins', '16 kg pkg.', '10 boxes x 12 pieces', '30 gift boxes', '24 pkgs. x 4 pieces', '24 - 500 g pkgs.',
'12 - 250 g pkgs.',
'12 - 355 ml cans', '20 - 450 g glasses', '100 - 250 g bags'];
let orderID: number = 10248;
for (let i: number = 0; i < 20000; i++) {
lazyLoadData.push({
'OrderID': orderID + i,
'CustomerID': customerid[Math.floor(Math.random() * customerid.length)],
'CustomerName': customername[Math.floor(Math.random() * customername.length)],
'CustomerAddress': customeraddress[Math.floor(Math.random() * customeraddress.length)],
'ProductName': product[Math.floor(Math.random() * product.length)],
'ProductID': i,
'Quantity': quantityperunit[Math.floor(Math.random() * quantityperunit.length)]
});
}
}
Offline mode
On remote data binding, all grid actions such as paging, sorting, editing, grouping, filtering, etc., process on server-side. To avoid post back for every action, set the grid to load all data on initialization and make the actions process in client-side. To enable this behavior, use the offline property of DataManager.
import { ColumnDirective, ColumnsDirective, GridComponent, PageSettingsModel, Page, Group, Sort } from '@syncfusion/ej2-react-grids';
import { DataManager, ODataAdaptor } from '@syncfusion/ej2-data';
import * as React from 'react';
function App() {
const pageSettings: PageSettingsModel = { pageSize: 7 };
const data: DataManager = new DataManager({
url: 'https://js.syncfusion.com/demos/ejServices/Wcf/Northwind.svc/Orders?$top=7',
adaptor: new ODataAdaptor(),
offline: true
});
return <div>
<GridComponent dataSource={data} height={315} allowPaging={true} pageSettings={pageSettings} allowSorting={true} allowGrouping={true}>
<ColumnsDirective>
<ColumnDirective field='OrderID' headerText='Order ID' width='120' textAlign="Right" />
<ColumnDirective field='CustomerID' headerText='Customer ID' width='150' />
<ColumnDirective field='ShipCity' headerText='Ship City' width='150' />
<ColumnDirective field='ShipName' headerText='Ship Name' width='150' />
</ColumnsDirective>
<Inject Services={[Page, Sort, Group]}/>
</GridComponent>
</div>
};
export default App;Fetch result from the DataManager query using external button
By default, Syncfusion Data Grid automatically binds a remote data source using the DataManager. However, in some scenarios, it may be necessary to fetch data dynamically from the server using a query triggered by an external button. This approach allows greater control over when and how data loads into the grid.
To achieve this, use the executeQuery method of DataManager with a query object. This method enables running a custom query and retrieving results dynamically.
The following example demonstrates the process of fetching data from the server when an external button is clicked and displaying a status message indicating the data fetch status.
import { ColumnDirective, ColumnsDirective, GridComponent, Page, Inject } from '@syncfusion/ej2-react-grids';
import React, { useState } from "react";
import { DataManager, WebApiAdaptor, Query } from "@syncfusion/ej2-data";
import { ButtonComponent } from "@syncfusion/ej2-react-buttons";
function App() {
const [statusMessage, setStatusMessage] = useState('');
const [setData, setDataSource] = useState([]);
const hostUrl = "https://services.syncfusion.com/react/production/";
const data = new DataManager({ url: hostUrl + 'api/Orders', adaptor: new WebApiAdaptor });
const executeQuery = () => {
setStatusMessage("Fetching data...");
data.executeQuery(new Query())
.then((response) => {
setDataSource(response.result);
setStatusMessage(`Data fetched successfully! Total Records: ${response.result.length}`);
})
.catch(() => {
setStatusMessage("Error fetching data!");
});
};
return (
<div>
<div style={{ margin: "5px 10px" }}>
<ButtonComponent onClick={executeQuery}>Execute Query</ButtonComponent>
</div>
<p style={{ textAlign: "center", color: "red" }}>{statusMessage}</p>
<GridComponent dataSource={setData} allowPaging={true} height={230}>
<ColumnsDirective>
<ColumnDirective field="OrderID" headerText="Order ID" width="120" textAlign="Right" />
<ColumnDirective field="CustomerID" headerText="Customer ID" width="160" />
<ColumnDirective field="EmployeeID" headerText="Employee ID" width="120" textAlign="Right" />
<ColumnDirective field="Freight" headerText="Freight" width="150" format="C2" textAlign="Right" />
<ColumnDirective field="ShipCountry" headerText="Ship Country" width="150" />
</ColumnsDirective>
<Inject services={[Page]} />
</GridComponent>
</div>
);
};
export default App;import { ColumnDirective, ColumnsDirective, GridComponent, Page, Inject } from '@syncfusion/ej2-react-grids';
import React, { useState } from "react";
import { DataManager, WebApiAdaptor, Query } from "@syncfusion/ej2-data";
import { ButtonComponent } from "@syncfusion/ej2-react-buttons";
function App() {
const [statusMessage, setStatusMessage] = useState('');
const [setData, setDataSource] = useState<Object[]>([]);
const hostUrl = "https://services.syncfusion.com/react/production/";
const data = new DataManager({ url: hostUrl + 'api/Orders', adaptor: new WebApiAdaptor });
const executeQuery = () => {
setStatusMessage("Fetching data...");
data.executeQuery(new Query())
.then((response) => {
setDataSource(response.result);
setStatusMessage(`Data fetched successfully! Total Records: ${response.result.length}`);
})
.catch(() => {
setStatusMessage("Error fetching data!");
});
};
return (
<div>
<div style={{ margin: "5px 10px" }}>
<ButtonComponent onClick={executeQuery}>Execute Query</ButtonComponent>
</div>
<p style={{ textAlign: "center", color: "red" }}>{statusMessage}</p>
<GridComponent dataSource={setData} allowPaging={true} height={230}>
<ColumnsDirective>
<ColumnDirective field="OrderID" headerText="Order ID" width="120" textAlign="Right" />
<ColumnDirective field="CustomerID" headerText="Customer ID" width="160" />
<ColumnDirective field="EmployeeID" headerText="Employee ID" width="120" textAlign="Right" />
<ColumnDirective field="Freight" headerText="Freight" width="150" format="C2" textAlign="Right" />
<ColumnDirective field="ShipCountry" headerText="Ship Country" width="150" />
</ColumnsDirective>
<Inject services={[Page]} />
</GridComponent>
</div>
);
};
export default App;