VirtualScroll
Virtual Scroll displays a virtual, "infinite" list. An array of records is passed to the virtual scroll containing the data to create templates for. The template created for each record, referred to as a cell, can consist of items, headers, and footers.
For performance reasons, not every record in the list is rendered at once; instead a small subset of records (enough to fill the viewport) are rendered and reused as the user scrolls.
The Basics
The array of records should be passed to the virtualScroll
property.
The data given to the virtualScroll
property must be an array. An item
template with the *virtualItem
property is required in the virtualScroll
.
The virtualScroll
and *virtualItem
properties can be added to any element.
<ion-list [virtualScroll]="items">
<ion-item *virtualItem="#item">
</ion-item>
</ion-list>
Section Headers and Footers
Section headers and footers are optional. They can be dynamically created
from developer-defined functions. For example, a large list of contacts
usually has a divider for each letter in the alphabet. Developers provide
their own custom function to be called on each record. The logic in the
custom function should determine whether to create the section template
and what data to provide to the template. The custom function should
return null
if a template shouldn't be created.
<ion-list [virtualScroll]="items" [headerFn]="myHeaderFn">
<ion-item-divider *virtualHeader="#header">
Header:
</ion-item-divider>
<ion-item *virtualItem="#item">
Item:
</ion-item>
</ion-list>
Below is an example of a custom function called on every record. It
gets passed the individual record, the record's index number,
and the entire array of records. In this example, after every 20
records a header will be inserted. So between the 19th and 20th records,
between the 39th and 40th, and so on, a <ion-item-divider>
will
be created and the template's data will come from the function's
returned data.
myHeaderFn(record, recordIndex, records) {
if (recordIndex % 20 === 0) {
return 'Header ' + recordIndex;
}
return null;
}
Approximate Widths and Heights
The approximate width and height of each template is used to help determine how many cells should be created, and to help calculate the height of the scrollable area. Note that the actual rendered size of each cell comes from the app's CSS, whereas this approximation is only used to help calculate initial dimensions.
It's also important to know that Ionic's default item sizes have slightly different heights between platforms, which is perfectly fine. An exact pixel-perfect size is not necessary, but a good estimation is important. Basically if each item is roughly 500px tall, rather than the default of 40px tall, it's extremely important to know for virtual scroll to calculate a good height.
Images Within Virtual Scroll
Ionic provides <ion-img>
to manage HTTP requests and image rendering.
Additionally, it includes a customizable placeholder element which shows
before the image has finished loading. While scrolling through items
quickly, <ion-img>
knows not to make any image requests, and only loads
the images that are viewable after scrolling. It's also important for app
developers to ensure image sizes are locked in, and after images have fully
loaded they do not change size and affect any other element sizes.
We recommend using our <ion-img>
element over the native <img>
element
because when an <img>
element is added to the DOM, it immediately
makes a HTTP request for the image file. HTTP requests, image
decoding, and image rendering can cause issues while scrolling. For virtual
scrolling, the natural effects of the <img>
are not desirable features.
<ion-list [virtualScroll]="items">
<ion-item *virtualItem="#item">
<ion-avatar item-left>
<ion-img [src]="item.avatarUrl"></ion-img>
</ion-avatar>
</ion-item>
</ion-list>
Performance Tips
- Use
<ion-img>
rather than<img>
so images are lazy loaded while scrolling. - Image sizes should be locked in, meaning the size of any element should not change after the image has loaded.
- Provide an approximate width and height so the virtual scroll can best calculate the cell height.
- Changing the dataset requires the entire virtual scroll to be reset, which is an expensive operation and should be avoided if possible.
- Do not perform any DOM manipulation within section header and footer functions. These functions are called for every record in the dataset, so please make sure they're performant.
Directive
selector: [virtualScroll]
Input Properties
Attr | Type | Details |
---|---|---|
virtualScroll | array |
The data that builds the templates within the virtual scroll.
This is the same data that you'd pass to |
bufferRatio | number |
The buffer ratio is used to decide how many cells
should get created when initially rendered. The number is a
multiplier against the viewable area's height. For example, if it
takes |
approxItemWidth | string |
The approximate width of each item template's cell.
This dimension is used to help determine how many cells should
be created when initialized, and to help calculate the height of
the scrollable area. This value can use either |
approxItemHeight | string |
The approximate height of each item template's cell.
This dimension is used to help determine how many cells should
be created when initialized, and to help calculate the height of
the scrollable area. This height value can only use |
approxHeaderWidth | string |
The approximate width of each header template's cell.
This dimension is used to help determine how many cells should
be created when initialized, and to help calculate the height of
the scrollable area. This value can use either |
approxHeaderHeight | string |
The approximate height of each header template's cell.
This dimension is used to help determine how many cells should
be created when initialized, and to help calculate the height of
the scrollable area. This height value can only use |
approxFooterWidth | string |
The approximate width of each footer template's cell.
This dimension is used to help determine how many cells should
be created when initialized, and to help calculate the height of
the scrollable area. This value can use either |
approxFooterHeight | string |
The approximate height of each footer template's cell.
This dimension is used to help determine how many cells should
be created when initialized, and to help calculate the height of
the scrollable area. This height value can only use |
headerFn | function |
Section headers and the data used within its given
template can be dynamically created by passing a function to |
footerFn | function |
Section footers and the data used within its given
template can be dynamically created by passing a function to |
virtualTrackBy | function |
Same as |