We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. Image for the cookie policy date
close icon

Server side pagination,sorting,grouping

Hi,

As of now in my application I am fetching all the data and binding it to grid and pagination,sorting and grouping is done on client side. I was wondering as the data will grow this will have performance issue like getting 5K records at a time and binding them to grid.  Do you think this will be an issue binding such a huge records to grid?
So I wanted to understand how can I get server side pagination/sorting and grouping implemented.

Here is how I am binding data to grid - 
on init -
GetAll() {
        this._myService.getAll('', this.maxResultCount, this.skipCount).subscribe(result => {
            this.dataList = result.items;
        })
    }
and dataList is used as datasource for the grid.
<ejs-grid #dataGrid [dataSource]='dataList ' [enableHover]='false' [searchSettings]='false' allowPaging='true' allowSorting="true" [toolbar]='false' [allowGrouping]="true" [groupSettings]="groupOptions"  [pageSettings]='pageSettings'>
     <e-column ...></e-column>
</ejs-grid>

If user is sorting on a column which event gets triggered - where I can call my service method and pass the name of column to sort?
If user is navigating between pages - which event is triggered - where I can call my service method and pass the pageindex or count to skip records?
If user is grouping - which event is triggered - and what is the expected data structure and how does it work with pagination? Or can I just sort records based on grouping column and do grouping on client side?

Your help is much appreciated. 

Thanks,
Sunita

14 Replies

TS Thavasianand Sankaranarayanan Syncfusion Team April 11, 2019 12:23 PM UTC

Hi Sunita, 

Greeting from Syncfusion. 

By default, Grid rendered based on the cell element while using large amount of data then it take considerable time to render the Grid. As per your requirement, we suggest you to bind the actionBegin event to find out grid actions such as paging, sorting, filtering etc., and their arguments (current page ,previous page, sort direction and column name etc). 



We have data manager to access remote(server) data so please check the below documentation for more information about data binding based on your service you may use any of our adaptor. 




Note: By default, Grouping will be done by client side only. 

Please get back to us if you need further assistance.  

Regards, 
Thavasianand S. 



SU Sunita April 13, 2019 04:46 PM UTC




Hello Thavasianand,

As per your suggestion "actionBegin event" helps me to do server side pagination and sorting. Thanks for your help. But I am not sure how to do grouping. If it is done on client side then it will be based on the records as per page size and will not consider all records in db.

Below url talks about server side grouping but I am not sure how can I implement it in our application -

Can you please guide me on how can I achieve server side grouping ? Or is it possible only to return grouped rows first and then on expand load its respective rows (lazy loading) ? I need grouping feature of grid but it has to be server side.

Help appreciated.

Thanks,
Sunita


SU Sunita April 14, 2019 12:55 PM UTC

Hello Thavasianand,

This is again related to server side pagination I am trying to implement using actionBegin() event. But every time I click on any page number it resets to 1. Please find below code - I am not sure what is wrong with my code. actionBegin() for paging is fired twice.

                                  [pageSettings]='pageSettings' (actionBegin)="onActionBegin($event)" (dataBound)="dataBound($event)" (beforeDataBound)="beforeDataBound($event)">
pagesettings:
this.pageSettings = { pageSizes: true, pageSize: this.defaultPageSzie, pageCount: 0, currentPage: 1 };

code- 
Note: on init I am calling GetAll(); (for the first time binding)





Help me to resolve this issue.

Thank,
Sunita


TS Thavasianand Sankaranarayanan Syncfusion Team April 15, 2019 01:25 PM UTC

Hi Sunita, 

Thanks for your update. 

In your application, you are assigning value for currentPage(pageSettings) property dynamically so that it call actionBegin event twice. As per your requirement, we suggest you to use observables that will helps you to bind the custom data and handled Grid actions in server side. Based on the dataStateChange event arguments you can perform grid actions and return result to Grid. 

Please refer the below help docuemantion link for more information.  


If you are not comfortable with async-pipe then we suggest you to refer the below link(Here we have subscribe the observables). 


Regards, 
Thavasianand S. 



SU Sunita April 15, 2019 04:25 PM UTC

Hello Thavasianand,

I will try to implement it is using observables and async pipe. Thanks for your suggestion. Hope it works as per my requirement.

Can you please also help me with grouping - 

 If it is done on client side then it will be based on the records as per page and will not consider all records in db.

Below url talks about server side grouping but I am not sure how can I implement it when using observables and async pipe -

Can you please guide me on how can I achieve server side grouping ? Or is it possible only to return grouped rows first and then on expand load its respective rows (lazy loading) ? I need grouping feature of grid but it has to be server side.


Thanks,
Sunita


TS Thavasianand Sankaranarayanan Syncfusion Team April 17, 2019 03:11 AM UTC

Hi Sunita, 

Thanks for your update. 

As per your suggestion, we have created a sample(Angular with Core) and perform grouping in sever side(like EJ1). In the below sample, we have used urlAdaptor and handle the grid actions in server side. Please refer the below sample and documentation for more information. 

[ClientApp/app/components/fetchdata.component.ts] 
 ngOnInit(): void { 
    this.data = new DataManager({ 
        url: 'Home/UrlDatasource', 
        adaptor: new UrlAdaptor 
    }); 
  } 

[HomeController.cs] 
     public IActionResult UrlDatasource([FromBody]DataManagerRequest dm) 
        { 
 
            IEnumerable DataSource = OrdersDetails.GetAllRecords(); 
            DataOperations operation = new DataOperations(); 
            if (dm.Sorted != null && dm.Sorted.Count > 0) //Sorting 
            { 
                DataSource = operation.PerformSorting(DataSource, dm.Sorted); 
            } 
            if (dm.Where != null && dm.Where.Count > 0) //Filtering 
            { 
                DataSource = operation.PerformFiltering(DataSource, dm.Where, dm.Where[0].Operator); 
            } 
            IEnumerable GroupDs = new List<object>(); ; 
            if (dm.Group != null) 
            { 
               GroupDs = operation.PerformSelect(DataSource, dm.Group); 
            } 
 
            int count = DataSource.Cast<OrdersDetails>().Count(); 
            if (dm.Skip != 0) 
            { 
                DataSource = operation.PerformSkip(DataSource, dm.Skip);   //Paging 
            } 
            if (dm.Take != 0) 
            { 
                DataSource = operation.PerformTake(DataSource, dm.Take); 
            } 
            return dm.RequiresCounts ? Json(new { result = DataSource, count = count, groupDs = GroupDs }) : Json(DataSource); 
        } 

  
 



Regards, 
Thavasianand S. 



SU Sunita April 17, 2019 05:50 AM UTC

Hello Thavasianand,

As per your suggestion I have already made changes to application to use observables. Please suggest server side grouping based on that.

Also as per your code below - all records are fetched at once on web-server again can be performance issue.

Does the grid support lazy loading - getting grouped rows first and then on expand of grouped header row load child rows? 

Thanks,
Sunita


TS Thavasianand Sankaranarayanan Syncfusion Team April 22, 2019 12:25 PM UTC

Hi Sunita, 

Thanks for your update. 

By default, while perform grouping it send server request(server side grouping) based on the field we have returned the corresponding grouped column records in server side (while grouping) and then calculate the group caption(14 items) and aggregates at client side using the server data. 

Currently, we don’t have support like lazy loading in Grid. We are checking the feasibility at our end we will let you know once the feature validation complete. 

Until then we appreciate your patience. 

Regards, 
Thavasianand S. 



SR Srinivas September 20, 2019 06:36 AM UTC

Hi

I am having difficulty in implementing the paging on the grid, it is not showing pages at all.I implemented several grids with paging in other functionality using local data binding, but with remote I am unable to figure out.

html:
<ejs-grid #customerGrid id='grid' class="margin-top-5 expense-grid-margin pane"
allowSorting="true" height='100%' width='100%' allowPaging='true' [allowSelection]='true'
[dataSource]='data | async' (dataSourceChanged)='dataSourceChanged($event)'
(dataStateChange)= 'dataStateChange($event)' [pageSettings]='pageOptions'>
 <e-columns>
<e-column type='checkbox' width='30'></e-column>
<e-column field='name' headerText='Name' width='110' [validationRules]='validateRule' hideAtMedia='(min-width: 600px)'></e-column>
<e-column field='id' headerText='Id' isPrimaryKey='true' [visible]='false'></e-column>
</e-columns>
</ejs-grid>

component:
constructor(private service: CustomerDataService) {
this.data = service;
}

public dataStateChange(state: DataStateChangeEventArgs): void {
this.service.execute(state);
}

public ngOnInit(): void {
this.pageOptions = { pageSize: 10, pageCount: 5, pageSizes: true};
this.validateRule = {required: true};
const state: any = { skip: 1, take: 10 };
this.service.execute(state);
}
service:
public execute(state: any, headers?: HttpHeaders | null): void {
this.getData(state, headers).subscribe(x => super.next(x as DataStateChangeEventArgs));
}

protected getData(state: DataStateChangeEventArgs, headers?: HttpHeaders | null): Observable<DataStateChangeEventArgs> {
const pageQuery = `pageNumber=${state.skip}&pageSize=${state.take}`;
const baseFilter = new BaseFilter(state.skip, state.take);
let sortQuery = '';
const d = 'd';
const results = 'results';
const count = '__count';
if ((state.sorted || []).length) {
sortQuery = `&$orderby=` + state.sorted.map((obj: Sorts) => {
return obj.direction === 'descending' ? `${obj.name} desc` : obj.name;
}).
reverse().join(',');
}
const expandedHeaders = this.prepareHeader(headers);

return this.http.get(this.baseUrl + '?pageNumber=' + baseFilter.pageNumber + '&pageSize=' + baseFilter.pageSize, expandedHeaders)
.
map((res: any) => ({
result: state.take > 0 ? res.data.slice(state.skip, state.skip + state.take) : res,
count: res.totalCount
} as DataResult))
.
pipe((data: any) => data);
}
response json:(data has just one row, but it returns 10 rows actually)
{"data":[{"id":4927,"name":"test customer","phone":"6301482799","customerAdded":"2019-09-20"],"pageNumber":1,"nextPageNumber":2,"prevPageNumber":1,"lastPage":false,"firstPage":true,"pageSize":10,"totalCount":4746,"totalPageCount":475}


PS Pavithra Subramaniyam Syncfusion Team September 23, 2019 09:22 AM UTC

Hi Srinivas, 

Thanks for contacting Syncfusion support. 

We have validated the provided information and code example. We suspect that in your application, you are not returning data properly so that it cause the reported problem. We suggest you to return the result and count properly because while using custom binding(or remote data) then we have bind the data to Grid based on the result (JSON object) that you are returned from server. 

Please refer the below demo sample for more information. 

 
Regards, 
Pavithra S. 



SR Srinivas September 23, 2019 04:09 PM UTC

Thanks Pavithra,

the response comes as JSON already with two properties result as an array and count as number, thats why I commented response.json() see sample data response

{"result":[{"id":4953,"name":"Amit Kurud","phone":"333222222","customerAdded":"2019-09-23","customerId":"CUS5503266","referralCode":"CgCHbz","notifyReceiver":false,"deviceType":"ANDROID","deviceMake":"OnePlus","deviceModel":"ONEPLUS A6010","os":"1.0.49","premium":false,"webSignup":false},{"id":4952,"name":"Swarup Denre","phone":"322112333","customerAdded":"2019-09-23","customerId":"CUS5502266","referralCode":"6Y6crt","notifyReceiver":false,"deviceType":"ANDROID","deviceMake":"samsung","deviceModel":"SM-A505F","os":"1.0.49","premium":false,"webSignup":false}],"count":4772}

return this.http.get(this.baseUrl + '?pageNumber=' + baseFilter.pageNumber + '&pageSize=' + baseFilter.pageSize, expandedHeaders)
// .pipe(map((response: any) => response.json()))
.pipe(map((response: any) => (<DataResult>{
result: response.result,
count: response.count
})))
.pipe((data: any) => data);


TS Thavasianand Sankaranarayanan Syncfusion Team September 24, 2019 11:55 AM UTC

Hi Srinivas, 

Thanks for your update. 

By default, if you are returning the result and count then we have bind the data(result) to Grid. We have created a sample for your reference, please refer the sample for more information.  


Note: previously provided code snippet you are apply initial skip count as 1 so it return record from 2nd

Could you please share the issue details and if possible share the sample(or reproduce at our sample) and video to demonstrate the problem that will be helpful for us to validate further and to provide a better solution as soon as possible. 

Regards, 
Thavasianand S. 



NS Neha Singh August 31, 2020 08:03 PM UTC

Hello Team,

I need to integrate server side paging and filtering. Can you please provide a sample of this? As in the thread I am getting confused...
Scenario :
Service Call -> url +'?pageSize=' +
        param.pageSize +
        '&pageNo=' +
        param.pageNo
In Query Param I need to pass -> pageSize: 10pageNo: 1} // To fetch the response of corresponding page
HTML ->
<ejs-grid
    [dataSource]="data"
    [allowPaging]="false"
    [allowSorting]="true"
    [allowFiltering]="true"
    [filterSettings]="filterSettings"
  >
    <e-columns>
      <e-column
        field="Id"
        headerText="id"
        textAlign="Left"
        width="50"
      ></e-column>
      <e-column
        field="Name"
        headerText="Name"
        textAlign="Left"
        width="50"
      ></e-column>
      <e-column
        field="location"
        headerText="Loc"
        textAlign="Left"
        width="60"
      ></e-column>
      <e-column
        field="deviceTimestamp"
        type="date"
        headerText="Time"
        textAlign="Left"
        width="80"
      ></e-column>
</e-columns>
 </ejs-grid>


BS Balaji Sekar Syncfusion Team September 2, 2020 01:16 PM UTC

Hi Sunita, 
 
Thanks for your patience. 
 
Query #1: I need to integrate server side filtering in the custom databinding 
 
Based on your query you can filtering the Grid columns with custom binding data using dataStateChange event of Grid component 
 
In dataStateChange event, we have call the remote service based on the filterchoicerequest”, “filtersearchbegin requestType. 
 
When you perform the filtering action, you need to return result data alone in JSON object format. 
 
 
@Component({ 
  selector: "control-content", 
  templateUrl: `async-pipe.html`, 
  providers: [OrdersService] 
}) 
export class AsyncPipeComponent { 
  public state: DataStateChangeEventArgs; 
  public filterOptions = { type: "Excel" }; 
 
  constructor(public service: OrdersService) { 
    this.data = service; 
  } 
 
  public dataStateChange(state: DataStateChangeEventArgs): void { 
    if ( 
      state.action.requestType === "filterchoicerequest" || state.action.requestType === "filtersearchbegin" 
    ) { 
      this.service.getData(state).subscribe(e => state.dataSource(e)); // for filterchoicerequest and filtersearchbegin you need to return JSON object alone no need to send count  
    } else {  
      this.service.execute(state); 
    } 
  } 
 
public execute(state: any): void { 
  this.getData(state).subscribe(x => super.next(x)); 
} 
 
public getData(state: DataStateChangeEventArgs): Observable<DataStateChangeEventArgs> { 
 . . . . . 
  return this.http 
    .get(`${this.BASE_URL}?${pageQuery}${sortQuery}${filterQuery}&$count=true`) 
    .pipe(map((response: any) => response.json())) 
    .pipe(map((response: any) => { 
      return state.dataSource === undefined ? (<DataResult>{ 
        result: response['value'], 
        count: parseInt(response['@odata.count'], 10), 
      }) : response['value']; 
    })) 
    .pipe(map((data: any) => data)); 
} 
} 



Query #2: I need to integrate server side server-side paging 
 
We analyzed your query with the information provided and we need to confirm that you want to pass pageSize, pageNo values instead of skip, take option to get current page records from remote service data. 

If we misunderstood your requirement please share more details about your query that will help to validate further. 

Regards, 
Balaji Sekar 


Loader.
Live Chat Icon For mobile
Up arrow icon