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

How to fetch the data when the scrollbar reaches the end of the scroller in Angular Grid

Hi,
 I want to know the usage of infinite scrolling but with data fetched from backend i.e using api as we scroll to bottom infinitely,
As of now you provided a method for infinite scrolling when whole data fetched at initial time but my requirement is to fetch records as we scroll down using api. as we have odata options like $top,$skip queries.

10 Replies 1 reply marked as answer

RR Rajapandi Ravi Syncfusion Team August 5, 2020 06:03 AM

Hi Goutham, 

Greetings from syncfusion support 

Based on your query we found that you like to fetch the data when the scrollbar reaches the end of the scroller. By default the infinite scrolling does not load the whole data initially.  

The infinite scrolling feature works like the lazy loading concept, which means the buffer data is loaded only when the scrollbar reaches the end of the scroller. To enable Infinite scrolling, set enableInfiniteScrolling property as true.  

Please refer the below code example and sample for more information. 

App.component.ts     
 
export class AppComponent { 
    public data: DataManager; 
    public initialPage: Object; 

    ngOnInit(): void { 
         this.data = new DataManager({ 
            url: 'https://js.syncfusion.com/demos/ejServices/Wcf/Northwind.svc/Orders', 
            adaptor: new ODataAdaptor(), 
            crossDomain: true 
        }); 
    } 
 



Screenshot: 

 


Regards, 
Rajapandi R

Marked as answer

AC Aparna Cilusani replied to Rajapandi Ravi November 26, 2021 03:13 AM

how we need to call a api instead of url to get the data from the server




RR Rajapandi Ravi Syncfusion Team November 29, 2021 04:08 AM

Hi Aparna, 

Thanks for the update 

Before proceeding with your query, we would like to share the available data-bindings in EJ2 Grid. 
 
If you are using WebAPI service or OData or SQL or any DataTable or List binding in your application, then we suggest you use Syncfusion inbuilt adaptor of DataManager to perform action on your service. 
 
You can choose the adaptors based on your Database. Refer to the below documentation which detailly illustrates available data adaptors in EJ2. 





For each Grid data-action like Filtering, Sorting, Paging, Scrolling etc., we send the correspond query to the server based on the data-adaptors. You can execute the queries with your data and return results with required format to the Grid. 
 
If you are using any custom service, we suggest you use custom-binding feature to bind the data to the Grid. We would like to share the behavior of custom-binding in EJ2 Grid. 

For every grid action(such as FilterPage, etc.,), we have triggered the dataStateChange event and, in that event arguments we have send the corresponding action details(like skip, take, filter field, value, sort direction, etc.,) based on that, you can perform the action in your service and return the data as a result and count object.  

Note: ‘dataStateChange’ event is not triggered at the Grid initial render. If you are using a remote service, you need to call your remote service by manually with a pagination query (need to set skip value as 0 and take value based on your pageSize of pageSettings in Grid. If you are not defined pageSize in pageSettings, you need to send the default value 12 ) in mounted. Please return the result like as “{result: […], count: …}” format to Grid. 

dataSourceChanged’ event is triggered when performing CRUD action in Grid. You can perform the CRUD action in your service using action details from this event and, you need to call the endEdit method to indicate the completion of save operation. 


                               https://ej2.syncfusion.com/angular/documentation/grid/observables/#perform-crud-operations 

 
If it does not meet your requirement, please share the details about what type of API you are binding in your application. 

Rajapandi R 



AC Aparna Cilusani replied to Rajapandi Ravi November 30, 2021 12:33 AM

Hi Rajapandi Ravi,


Thank you for your reply. 


How do we get, on scroll event in infinite scrolling. I want to fetch the data from custom service on end of every scroll. 



RR Rajapandi Ravi Syncfusion Team December 1, 2021 04:53 AM

Hi Aparna, 
 
Thanks for the update 

In EJ2 Grid Infinite scrolling for each time scrolling request will be send to the server. 

From your update, we could see that you are using custom binding (Observable binding). We have prepared sample with infinite scrolling with custom binding. In that sample the dataStateChange event will be triggered for each grid action like paging, sorting, filtering, etc., with the arguments. By using these arguments, you can execute your own service and return the data to the grid with the result and count pair. Please refer the below code example and sample for better understanding. 

[App.component.html] 
<div class="control-section"> 
    <ejs-grid [dataSource]='data | async' #grid [height]=400 [enableInfiniteScrolling]='true' [pageSettings]='pageOptions' (dataStateChange)= 'dataStateChange($event)'> 
        <e-columns> 
            <e-column field= "OrderID" headerText="Order ID" width="130" ></e-column> 
            <e-column field= "CustomerID" headerText="Customer Name" width="150"></e-column> 
            <e-column field= "ShipName" headerText="Ship Name" width="200"></e-column> 
            <e-column field= "ShipCity" headerText="Ship City" width="150"></e-column> 
        </e-columns> 
    </ejs-grid> 
</div> 
[App.component.ts] 
import { ComponentOnInitInject,ViewChild } from '@angular/core'; 
import { Observable } from 'rxjs'; 
import { OrdersService } from './order.service'; 
import { DataStateChangeEventArgs,PdfExportProperties,ExcelExportProperties,ToolbarItems,IFilter,Filter } from '@syncfusion/ej2-grids'; 
import { GridComponent } from '@syncfusion/ej2-angular-grids'; 
import { ClickEventArgs } from '@syncfusion/ej2-navigations' 
 
@Component({ 
    selector: 'app-root', 
    templateUrl: 'app.component.html', 
    providers: [OrdersService], 
}) 
export class AppComponent { 
    public data: Observable<DataStateChangeEventArgs>; 
    public pageOptions: Object; 
    public count = 0; 
    public printData: Object[]; 
    @ViewChild('grid', {statictrue}) 
    public grid: GridComponent; 
    public state: DataStateChangeEventArgs; 
    public toolbarOptions: ToolbarItems[]; 
    constructorpublic service: OrdersService) { 
        this.data = service; 
    } 
 
    public dataStateChange(state: DataStateChangeEventArgs): void { 
// for each time the scroller reaches the end this event will be invoked  
with the parameters of skip and take  
// here instead using the service you can apply the data and return as result and count here 
        this.service.execute(state); 
    } 
 
    public ngOnInit(): void { 
        this.pageOptions = { pageSize: 50 }; 
// for initial rendering define the records to binding the Grid 
        let state = { skip: 0, take: 50 }; 
        this.service.execute(state); 
    } 
} 
 
[OrderService.ts] 
import { Injectable } from '@angular/core'; 
import { Http } from '@angular/http'; 
import { DataStateChangeEventArgsSortsDataResult } from '@syncfusion/ej2-angular-grids' 
import { Observable } from 'rxjs'; 
import { Subject } from 'rxjs'; 
import { map } from 'rxjs/operators'; 
 
@Injectable() 
export class OrdersService extends Subject<DataStateChangeEventArgs> { 
    private BASE_URL = 'https://js.syncfusion.com/demos/ejServices/Wcf/Northwind.svc/Orders' 
 
    constructor(private http: Http) { 
        super(); 
    } 
 
    public execute(state: any): void { 
        this.getData(state).subscribe(x => super.next(x)); 
    } 
 
    public getData(state: DataStateChangeEventArgs): Observable<DataStateChangeEventArgs> { 
      console.log(state.action) 
        const pageQuery = `$skip=${state.skip}&$top=${state.take}`; 
        let sortQuery: string = ''; 
 
        if ((state.sorted || []).length) { 
            sortQuery = `&$orderby=` + state.sorted.map((obj: Sorts) => { 
                return obj.direction === 'descending' ? `${obj.name} desc` : obj.name; 
            }).reverse().join(','); 
        } 
 
        return this.http  
           .get(`${this.BASE_URL}?${pageQuery}${sortQuery}&$inlinecount=allpages&$format=json` 
           .pipe(map((response: any) => response.json())) 
           .pipe(map((response: any) => (<DataResult>{ 
// here we are returning the 50 records to be displayed in the Grid 
                result: response['d']['results'], 
                count: parseInt(response['d']['__count'], 10) 
// here we are returning the data as Object of result and count 
        }))) 
        .pipe((data: any) => data); 
    } 
} 


Refer the below which illustrates the limitations of infinite scrolling and observables binding.
https://ej2.syncfusion.com/angular/documentation/grid/infinite-scroll/#limitations-for-infinite-scrolling 

Please get back to us if you need further assistance on this. 

Regards, 
Rajapandi R 



GH Ganesh Harihar June 15, 2022 03:10 AM

Hello Rajapandi Ravi,

I have implemented the above example but I have to add filtering functionality with the type 'Menu' and filter 'CheckBox' but after clicking on the filter icon it's just showing loader it's not able to get all the values for the filtering. Can't it just show all the loaded values for that column?

Here is the Url of implementation: https://stackblitz.com/edit/angular-infine-scroll-custombinding-r8yc4e?file=app.component.html

Thanks in advance.

Regards,

Ganesh Harihar



RR Rajapandi Ravi Syncfusion Team June 16, 2022 06:15 AM

Hi Ganesh,


Thanks for the update.


Currently, we are validating your query with your shared information, and we will update you the details on or before 20th June 2022. Until then we appreciate your patience.


Regards,

Rajapandi R



RR Rajapandi Ravi Syncfusion Team June 20, 2022 04:28 AM

Hi Ganesh,


Thanks for your patience


In custom binding when the filter/sort/page actions are performed in the Grid, the action details will be returned in the dataStateChange event as shown in the below image(shows filter action details),



From this event you need to form the filter/page/sort queries in the format as required by your server, process the action and bind the result to the Grid dataSource as an object of ‘result’ and ‘count’.


More details on custom binding can be checked in the below documentation link,


Custom binding: https://ej2.syncfusion.com/angular/documentation/grid/observables/#handling-grid-actions


Regards,

Rajapandi R



GH Ganesh Harihar June 21, 2022 01:45 AM

Hello Rajapandi Ravi,

Thank you for the response but if you have noticed I did the same thing in sample prepared after clicking on the filter icon it throws an error. Following is the sample URL if possible edit that sample and make filters work on 'Customer Name' column.

https://stackblitz.com/edit/angular-infine-scroll-custombinding-r8yc4e?file=app.component.html

Attached screenshot of the error also.

Regards,

Ganesh Harihar


Attachment: Filter_Error_11dc6654.zip


RR Rajapandi Ravi Syncfusion Team June 22, 2022 05:23 AM

Hi Ganesh,


Thanks for the update.


We have checked your query and we could see that you like to use the Excel Filter in the Custom binding. For every grid action(such as FilterPage, etc.,), we have triggered the dataStateChange event and, in that event arguments, we have sent the corresponding action details(like skip, take, filter field, value, sort direction, etc.,) based on that, you can perform the action in your service and return the data as a result and count object.   


dataStateChange: https://ej2.syncfusion.com/angular/documentation/api/grid/#datastatechange


 

[app.component.ts] 

 

 

  public dataStateChange(state) { 

      // exectue your own service and perform the action with state queries and return the result and count data to the Grid 

      this.getAsyncData(state); 

    } 

  } 

 

  getAsyncData(state) { 

    if (state.where) { 

      var gridqueries = this.grid.getDataModule().generateQuery().queries

      var wherequery

      for (var i = 0i < gridqueries.lengthi++) { 

        if (gridqueries[i].fn == 'onWhere') { 

          wherequery = gridqueries[i].e

        } 

      } 

      new DataManager({ url: SERVICE_URIadaptor: new ODataAdaptor() }) 

        .executeQuery(new Query().where(wherequery).take(state.take).skip(state.skip)) 

        .then((eany=> { 

         // bind the result and count object to the Grid 

          this.grid.dataSource = { 

            result: e.actual['d']['results'], 

            count: parseInt(e.actual['d']['__count'], 10) 

          }; 

          return e

        }); 

    } else { 

      new DataManager({ url: SERVICE_URIadaptor: new ODataAdaptor() }) 

        .executeQuery(new Query().take(state.take).skip(state.skip)) 

        .then((eany=> { 

         // bind the result and count object to the Grid 

          this.grid.dataSource = { 

            result: e.actual['d']['results'], 

            count: parseInt(e.actual['d']['__count'], 10) 

          }; 

          return e

        }); 

    } 

  } 

 

 


Note: ‘dataStateChange’ event is not triggered at the Grid initial render. If you are using a remote service, you need to call your remote service by manually with a pagination query (need to set skip value as 0 and take value based on your pageSize of pageSettings in Grid. If you are not defined pageSize in pageSettings, you need to send the default value 12 ) in ngOnInIt. Please return the result like as “{result: […], count: …}” format
to Grid.  

 

[app.component.ts] 

 

 

  public ngOnInit(): void { 

    // load initial data by executing your own service with page query and bind result and count value to the Grid 

    new DataManager({ url: SERVICE_URIadaptor: new ODataAdaptor() }) 

      .executeQuery(new Query().take(12).skip(0).expand(['Employee']) 

      ) 

      .then((eany=> { 

        // bind the current page data to the grid dataSource with result and object format 

        this.grid.dataSource = { 

          result: e.actual['d']['results'], 

          count: parseInt(e.actual['d']['__count'], 10) 

        }; 

      }); 

  } 

 

 

When you open the filter dialog, the dataStateChange event with requestType (‘filterchoicerequest/stingfilterrequest’) will be triggered. In that event, you need to execute your service and bind the array of object to the state.dataSource method. 

When you search the value in the filter dialog, the dataStateChange event with requestType (‘filtersearchbegin’) will be triggered. In that event, you need to filter the value from your service based on the event argument and bind the array of objects to the state.dataSource method. 

 

[app.component.ts] 

 

  public dataStateChange(state) { 

    if ( 

      state.action && 

      (state.action.requestType == 'filterchoicerequest' || 

        state.action.requestType == 'filtersearchbegin' || 

        state.action.requestType == 'stringfilterrequest'

    ) { 

   // below code will be executed when open the filter dialog and perform search in the filter dialog 

      state.skip = 0

      // execute your service and bind the data for other columns 

      if (state.where) { 

        new DataManager({ url: SERVICE_URIadaptor: new ODataAdaptor() }).executeQuery

            new Query().where( state.where[0].field, state.where[0].operator, state.where[0].value

          ).then((eany=> { 

            // bind array of Objects 

            state.dataSource(e.result); 

          }); 

      } else { 

        new DataManager({ url: SERVICE_URIadaptor: new ODataAdaptor() }) 

          .executeQuery(new Query()) 

          .then((eany=> { 

            // bind array of Objects 

            state.dataSource(e.result); 

          }); 

      } 

    } else { 

      // exectue your own service and perform the action with state queries and return the result and count data to the Grid 

      this.getAsyncData(state); 

    } 

  } 

 

Find the below sample and documentation for your reference. 


Sample: https://stackblitz.com/edit/angular-ws2fqv-mxcxjs?file=app.component.html,app.component.ts


Custom-Binding: https://ej2.syncfusion.com/angular/documentation/grid/observables/


Excel Filtering in Custom-Binding: https://ej2.syncfusion.com/angular/documentation/grid/observables/#provide-excel-filter-data-source                            


Regards,

Rajapandi R


Loader.
Live Chat Icon For mobile
Up arrow icon