The load-on-demand feature is particularly useful in cases when data needs to be loaded in chunks (pages) to optimize bandwidth usage and improve the UX. There are two load-on-demand modes available:

  • Manual - in this mode the user needs to manually request the next data page
  • Auto - in this mode the next data page is automatically requested as the user approaches the end of the scrollable list

When more items need to be loaded, RadListView fires the loadMoreDataRequested event.

In addition, RadListView exposes the loadOnDemandBufferSize property which determines the count of items left to scroll which when reached triggers a loadMoreDataRequested event. This property is used when the load-on-demand mode is set to be Auto.


The following scenario demonstrates how the loadMoreDataRequested event is handled. In addition, an example of a custom load-on-demand view is also given. A custom load-on-demand view is provided via the TKListViewLoadOnDemandDirective which is used with the tkListLoadOnDemandTemplate selector. To feed RadListView with data we use an ObservableArray which provides smart data change notifications to RadListView. When the loadMoreDataRequested event is fired we push new items into the array which notifies the list that a change has occurred.

Example: The template

The following snippet shows the template used to create the UI for the scenario. It shows how a handler for the loadMoreDataRequested event is provided, as well as how a custom load-on-demand view is applied:

Example: The component

The following code snippet demonstrates the code behind the template. Here you see how the loadMoreDataRequested event is handled and how data is fed back to RadListView:

<RadListView [items]="dataItems" loadOnDemandMode="Manual" (loadMoreDataRequested)="onLoadMoreItemsRequested($event)">
export class ListViewFixedSizeManualComponent implements OnInit {
    private _dataItems: ObservableArray<DataItem>;
    private _numberOfAddedItems;
    private layout: ListViewLinearLayout;

    constructor(private _changeDetectionRef: ChangeDetectorRef) {

    ngOnInit() {
        this.layout = new ListViewLinearLayout();
        this.layout.scrollDirection = "Vertical";

    public get dataItems(): ObservableArray<DataItem> {
        return this._dataItems;

    public onLoadMoreItemsRequested(args: ListViewEventData) {
        const that = new WeakRef(this);
        setTimeout(function () {
            const listView: RadListView = args.object;
            const initialNumberOfItems = that.get()._numberOfAddedItems;
            for (let i = that.get()._numberOfAddedItems; i < initialNumberOfItems + 2; i++) {
                if (i > posts.names.length - 1) {
                    listView.loadOnDemandMode = ListViewLoadOnDemandMode[ListViewLoadOnDemandMode.None];

                const imageUri = androidApplication ? posts.images[i].toLowerCase() : posts.images[i];
                that.get()._dataItems.push(new DataItem(i, posts.names[i], "This is item description", posts.titles[i], posts.text[i], "res://" + imageUri));

        }, 1000);
        args.returnValue = true;

    private initDataItems() {
        this._dataItems = new ObservableArray<DataItem>();
        this._numberOfAddedItems = 0;
        for (let i = 0; i < posts.names.length - 15; i++) {
            if (androidApplication) {
                this._dataItems.push(new DataItem(i, posts.names[i], "This is item description", posts.titles[i], posts.text[i], "res://" + posts.images[i].toLowerCase()));
            else {
                this._dataItems.push(new DataItem(i, posts.names[i], "This is item description", posts.titles[i], posts.text[i], "res://" + posts.images[i]));