Infinite scroll in Angular TreeGrid component
25 Aug 202514 minutes to read
The infinite scrolling feature in the TreeGrid offers seamless handling of large datasets while maintaining high performance. Infinite scroll operates on a “load-on-demand” concept, where data is fetched only as needed. In default infinite scrolling mode, a new block of data is loaded each time the scrollbar reaches the end of the TreeGrid’s vertical scroller. This approach significantly improves the user experience and performance when working with extensive data collections.
In infinite scrolling, a block refers to the pageSize of the TreeGrid. If pageSize
is not explicitly set, it is calculated automatically based on the TreeGrid’s viewport height and row height.
To enable infinite scrolling, set enableInfiniteScrolling to true and define the content height using the height property.
In infinite scrolling, the TreeGrid will not initiate a new data request when revisiting the same page.
Theheight
property must be specified when usingenableInfiniteScrolling
.
The following example demonstrates how to enable infinite scroll in the TreeGrid:
import { NgModule,ViewChild } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { TreeGridModule } from '@syncfusion/ej2-angular-treegrid'
import { PageService, InfiniteScrollService } from '@syncfusion/ej2-angular-treegrid'
import { Component, OnInit } from '@angular/core';
import { dataSource, virtualData } from './datasource';
@Component({
imports: [TreeGridModule ],
providers: [PageService, InfiniteScrollService],
standalone: true,
selector: 'app-container',
template: `<ejs-treegrid #treegrid [dataSource]='data' [enableInfiniteScrolling]=true height=317 [pageSettings]='pageSettings' childMapping='Crew' [treeColumnIndex]='1' >
<e-columns>
<e-column field='TaskID' headerText='Player Jersey' width='120' textAlign='Right'></e-column>
<e-column field='FIELD1' headerText='Player Name' width='120'></e-column>
<e-column field='FIELD2' headerText='Year' width='100' textAlign='Right'></e-column>
<e-column field='FIELD3' headerText='Stint' width='120' textAlign='Right'></e-column>
<e-column field='FIELD4' headerText='TMID' width='120' textAlign='Right'></e-column>
</e-columns>
</ejs-treegrid>`
})
export class AppComponent implements OnInit {
public data?: Object[];
public pageSettings?: Object;
ngOnInit(): void {
dataSource();
this.data = virtualData;
this.pageSettings = {pageSize: 30};
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Number of blocks rendered during initial loading
The number of blocks to be initially rendered when the tree grid is loaded. Each block corresponds to a page size of the tree grid, resulting in the rendering of a certain number of row elements determined by multiplying the initial block size with the page size.
You can define the initial loading pages count by using infiniteScrollSettings.initialBlocks property. By default, this property loads three pages during the initial rendering. Subsequently, additional data is buffered and loaded based on either the page size or the number of rows rendered within the provided height.
The following an example of how you can use the initialBlocks
property to set the initial loading pages based on DropDownList input:
import { NgModule,ViewChild } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { TreeGridComponent, TreeGridModule } from '@syncfusion/ej2-angular-treegrid'
import { PageService, InfiniteScrollService } from '@syncfusion/ej2-angular-treegrid'
import { Component, OnInit} from '@angular/core';
import { dataSource, virtualData } from './datasource';
import { ChangeEventArgs, DropDownListModule } from '@syncfusion/ej2-angular-dropdowns'
@Component({
imports: [TreeGridModule,DropDownListModule ],
providers: [PageService, InfiniteScrollService],
standalone: true,
selector: 'app-container',
template: `<div style="display: flex">
<label style="padding: 30px 20px 0 0" > Select initialBlocks count: :</label>
<ejs-dropdownlist #dropdown id='value' style="padding: 26px 0 0 0" #sample index='0' width='220' [dataSource]='dropDownData' (change)='valueChange($event)' ></ejs-dropdownlist>
</div>
<ejs-treegrid #treegrid [dataSource]='data' [enableInfiniteScrolling]=true height=275 [infiniteScrollSettings]='infiniteScrollSettings' [pageSettings]='pageSettings' childMapping='Crew' [treeColumnIndex]='1' >
<e-columns>
<e-column field='TaskID' headerText='Player Jersey' width='120' textAlign='Right'></e-column>
<e-column field='FIELD1' headerText='Player Name' width='120'></e-column>
<e-column field='FIELD2' headerText='Year' width='100' textAlign='Right'></e-column>
<e-column field='FIELD3' headerText='Stint' width='120' textAlign='Right'></e-column>
<e-column field='FIELD4' headerText='TMID' width='120' textAlign='Right'></e-column>
</e-columns>
</ejs-treegrid>`
})
export class AppComponent implements OnInit {
public data?: Object[];
public pageSettings?: Object;
public infiniteScrollSettings?: Object;
@ViewChild('treegrid') public treegrid?: TreeGridComponent;
public dropDownData?: Object[] = [
{ text: 'Select count' },
{ text: '1', value: '1' },
{ text: '2', value: '2' },
{ text: '3', value: '3' },
{ text: '4', value: '4' },
{ text: '5', value: '5' },
{ text: '6', value: '6' },
{ text: '7', value: '7' }
];
ngOnInit(): void {
dataSource();
this.data = virtualData;
this.pageSettings = {pageSize: 30};
this.infiniteScrollSettings = { initialBlocks: 5};
}
valueChange(args: ChangeEventArgs): void {
(this.treegrid as TreeGridComponent).infiniteScrollSettings.initialBlocks = parseInt((args.value as string), 10);
(this.treegrid as TreeGridComponent).refresh();
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Efficient data caching and DOM management in cache mode
In TreeGrid cache mode, previously loaded blocks are reused when revisiting, minimizing data requests as you scroll back and forth. The maximum number of cached blocks is controlled by the infiniteScrollSettings.maxBlocks property (default is 3). When this limit is exceeded, the oldest block of row elements is removed from the cache to accommodate new rows.
To enable cache mode, set enableCache to true in infiniteScrollSettings. Set the maximum block count using maxBlocks
as needed.
The following example demonstrates enabling or disabling cache mode using a Switch component’s change event:
import { NgModule,ViewChild } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { TreeGridComponent, TreeGridModule } from '@syncfusion/ej2-angular-treegrid'
import { PageService, InfiniteScrollService } from '@syncfusion/ej2-angular-treegrid'
import { ChangeEventArgs, SwitchModule} from '@syncfusion/ej2-angular-buttons'
import { Component, OnInit } from '@angular/core';
import { dataSource, virtualData } from './datasource';
@Component({
imports: [TreeGridModule, SwitchModule ],
providers: [PageService, InfiniteScrollService],
standalone: true,
selector: 'app-container',
template: `<div style="padding: 20px 0px 20px 0px">
<label>Enable/Disable Cache mode</label>
<ejs-switch #switch id="switch" [checked]='true' (change)="toggleCacheMode($event)"></ejs-switch>
</div>
<ejs-treegrid #treegrid [dataSource]='data' [enableInfiniteScrolling]=true height=275 [infiniteScrollSettings]='infiniteScrollSettings' [pageSettings]='pageSettings' childMapping='Crew' [treeColumnIndex]='1' >
<e-columns>
<e-column field='TaskID' headerText='Player Jersey' width='120' textAlign='Right'></e-column>
<e-column field='FIELD1' headerText='Player Name' width='120'></e-column>
<e-column field='FIELD2' headerText='Year' width='100' textAlign='Right'></e-column>
<e-column field='FIELD3' headerText='Stint' width='120' textAlign='Right'></e-column>
<e-column field='FIELD4' headerText='TMID' width='120' textAlign='Right'></e-column>
</e-columns>
</ejs-treegrid>`
})
export class AppComponent implements OnInit {
public data?: Object[];
public pageSettings?: Object;
public infiniteScrollSettings?: Object;
@ViewChild('treegrid') public treegrid?: TreeGridComponent;
ngOnInit(): void {
dataSource();
this.data = virtualData;
this.pageSettings = {pageSize: 30};
this.infiniteScrollSettings = { enableCache: true};
}
toggleCacheMode(args:ChangeEventArgs): void {
(this.treegrid as TreeGridComponent).infiniteScrollSettings.enableCache = args.checked;
(this.treegrid as TreeGridComponent).refresh();
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Limitations
- Due to browser element height limitations, the maximum number of records loaded by TreeGrid is limited by browser capabilities.
- Always set a static height for the TreeGrid or its parent container when using infinite scrolling. Setting 100% height works only if the parent container has a fixed height.
- When infinite scrolling is enabled, copy-paste and drag-and-drop operations are limited to rows in the current viewport.
- Cell selection is not persisted in cache mode.
- Aggregate information is shown based only on current view items.
- Programmatic selection using selectRows and selectRow is not supported in infinite scrolling mode.
- Infinite scrolling is not compatible with:
- Batch editing
- Row/Cell editing
- Row spanning
- Column spanning
- Row template
- Row virtual scrolling
- Detail template
- Autofill
- Limitations with row drag and drop:
- In cache mode, the TreeGrid automatically refreshes if the number of content row elements (
tr
) exceeds the cache limit after a drop action. - With remote data, changes made via drag and drop affect only the UI. These changes are lost after a refresh unless they are updated in the backend. Use the rowDrop event to update your server and refresh the TreeGrid to display new data.
- In cache mode, the TreeGrid automatically refreshes if the number of content row elements (
- Infinite scrolling does not support rendering records in a collapsed state. All records need to be fully expanded on initial load for this feature to work.