Skip to content

Commit 5321ab3

Browse files
mmalerbajelbourn
authored andcommitted
docs(virtual-scroll): add live examples (#13327)
1 parent fd3eb6a commit 5321ab3

22 files changed

+311
-45
lines changed

src/cdk/scrolling/scrolling.md

Lines changed: 8 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,7 @@ rest.
2727
same API as [`*ngFor`](https://angular.io/api/common/NgForOf). The simplest usage just specifies the
2828
list of items:
2929

30-
```html
31-
<cdk-virtual-scroll-viewport itemSize="50">
32-
<div *cdkVirtualFor="let item of items">{{item}}</div>
33-
</cdk-virtual-scroll-viewport>
34-
```
30+
<!-- example(cdk-virtual-scroll-overview) -->
3531

3632
`*cdkVirtualFor` makes the following context variables available to the template:
3733

@@ -47,15 +43,7 @@ list of items:
4743
All of these apply to the index of the item in the data source, not the index in the rendered
4844
portion of the data.
4945

50-
```html
51-
<cdk-virtual-scroll-viewport itemSize="50">
52-
<div *cdkVirtualFor="let item of items;
53-
let index = index;
54-
let count = count">
55-
{{item}} ({{index}} of {{count}})
56-
</div>
57-
</cdk-virtual-scroll-viewport>
58-
```
46+
<!-- example(cdk-virtual-scroll-context) -->
5947

6048
A `trackBy` function can be specified and works the same as the `*ngFor` `trackBy`. The `index`
6149
passed to the tracking function will be the index in the data source, not the index in the rendered
@@ -68,11 +56,7 @@ is reused instead. The size of the view cache can be adjusted via the `templateC
6856
property; setting this size to `0` disables caching. If your templates are expensive in terms of
6957
memory you may wish to reduce this number to avoid spending too much memory on the template cache.
7058

71-
```html
72-
<cdk-virtual-scroll-viewport itemSize="50">
73-
<div *cdkVirtualFor="let item of items; templateCacheSize: 0">{{item}}</div>
74-
</cdk-virtual-scroll-viewport>
75-
```
59+
<!-- example(cdk-virtual-scroll-template-cache) -->
7660

7761
##### Specifying data
7862
`*cdkVirtualFor` accepts data from an `Array`, `Observable<Array>`, or `DataSource`. The
@@ -83,17 +67,13 @@ data array that should be rendered. The viewport will call `disconnect` when the
8367
destroyed, which may be the right time to clean up any subscriptions that were registered during the
8468
connect process.
8569

70+
<!-- example(cdk-virtual-scroll-data-source) -->
71+
8672
#### Scrolling over fixed size items
8773
When all items are the same fixed size, you can use the `FixedSizeVirtualScrollStrategy`. This can
8874
be easily added to your viewport using the `itemSize` directive. The advantage of this constraint is
8975
that it allows for better performance, since items do not need to be measured as they are rendered.
9076

91-
```html
92-
<cdk-virtual-scroll-viewport itemSize="50">
93-
...
94-
</cdk-virtual-scroll-viewport>
95-
```
96-
9777
The fixed size strategy also supports setting a couple of buffer parameters that determine how much
9878
extra content is rendered beyond what is visible in the viewport. The first of these parameters is
9979
`minBufferPx`. The `minBufferPx` is the minimum amount of content buffer (in pixels) that the
@@ -108,11 +88,7 @@ remaining. Since this is below `minBufferPx` the viewport must render more buffe
10888
least enough buffer to get back to `maxBufferPx`. In this case, it renders 4 items (an additional
10989
`200px`) to bring the total buffer size to `290px`, back above `maxBufferPx`.
11090

111-
```html
112-
<cdk-virtual-scroll-viewport itemSize="50" minBufferPx="100" maxBufferPx="250">
113-
...
114-
</cdk-virtual-scroll-viewport>
115-
```
91+
<!-- example(cdk-virtual-scroll-fixed-buffer) -->
11692

11793
Other virtual scrolling strategies can be implemented by extending `VirtualScrollStrategy`. An
11894
autosize strategy that works on elements of differing sizes is currently being developed in
@@ -125,11 +101,7 @@ out horizontally via CSS. To do this you may want to target CSS at
125101
`.cdk-virtual-scroll-content-wrapper` which is the wrapper element that contains the rendered
126102
content.
127103

128-
```html
129-
<cdk-virtual-scroll-viewport itemSize="50" orientation="horizontal">
130-
...
131-
</cdk-virtual-scroll-viewport>
132-
```
104+
<!-- example(cdk-virtual-scroll-horizontal) -->
133105

134106
### Elements with parent tag requirements
135107
Some HTML elements such as `<tr>` and `<li>` have limitations on the kinds of parent elements they
@@ -138,13 +110,4 @@ their proper parent, and then wrap the whole thing in a `cdk-virtual-scroll-view
138110
that the parent does not introduce additional space (e.g. via `margin` or `padding`) as it will
139111
interfere with the scrolling.
140112

141-
```html
142-
<cdk-virtual-scroll-viewport itemSize="50">
143-
<table>
144-
<tr *cdkVirtualFor="let row of rows">
145-
<td>{{row.first}}</td>
146-
<td>{{row.second}}</td>
147-
</tr>
148-
</table>
149-
</cdk-virtual-scroll-viewport>
150-
```
113+
<!-- example(cdk-virtual-scroll-dl) -->
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.example-viewport {
2+
height: 200px;
3+
width: 200px;
4+
border: 1px solid black;
5+
}
6+
7+
.example-item-detail {
8+
height: 18px;
9+
}
10+
11+
.example-alternate {
12+
background: rgba(127, 127, 127, 0.3);
13+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<cdk-virtual-scroll-viewport [itemSize]="18 * 7" class="example-viewport">
2+
<div *cdkVirtualFor="let item of items;
3+
let index = index;
4+
let count = count;
5+
let first = first;
6+
let last = last;
7+
let even = even;
8+
let odd = odd;" [class.example-alternate]="odd">
9+
<div class="example-item-detail">Item: {{item}}</div>
10+
<div class="example-item-detail">Index: {{index}}</div>
11+
<div class="example-item-detail">Count: {{count}}</div>
12+
<div class="example-item-detail">First: {{first ? 'Yes' : 'No'}}</div>
13+
<div class="example-item-detail">Last: {{last ? 'Yes' : 'No'}}</div>
14+
<div class="example-item-detail">Event: {{even ? 'Yes' : 'No'}}</div>
15+
<div class="example-item-detail">Odd: {{odd ? 'Yes' : 'No'}}</div>
16+
</div>
17+
</cdk-virtual-scroll-viewport>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import {ChangeDetectionStrategy, Component} from '@angular/core';
2+
3+
/** @title Virtual scroll context variables */
4+
@Component({
5+
selector: 'cdk-virtual-scroll-context-example',
6+
styleUrls: ['cdk-virtual-scroll-context-example.css'],
7+
templateUrl: 'cdk-virtual-scroll-context-example.html',
8+
changeDetection: ChangeDetectionStrategy.OnPush,
9+
})
10+
export class CdkVirtualScrollContextExample {
11+
items = Array.from({length: 100000}).map((_, i) => `Item #${i}`);
12+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.example-viewport {
2+
height: 200px;
3+
width: 200px;
4+
border: 1px solid black;
5+
}
6+
7+
.example-item {
8+
height: 50px;
9+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<cdk-virtual-scroll-viewport itemSize="50" class="example-viewport">
2+
<div *cdkVirtualFor="let item of ds" class="example-item">{{item || 'Loading...'}}</div>
3+
</cdk-virtual-scroll-viewport>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import {CollectionViewer, DataSource} from '@angular/cdk/collections';
2+
import {ChangeDetectionStrategy, Component} from '@angular/core';
3+
import {BehaviorSubject, Observable, Subscription} from 'rxjs';
4+
5+
/** @title Virtual scroll with a custom data source */
6+
@Component({
7+
selector: 'cdk-virtual-scroll-data-source-example',
8+
styleUrls: ['cdk-virtual-scroll-data-source-example.css'],
9+
templateUrl: 'cdk-virtual-scroll-data-source-example.html',
10+
changeDetection: ChangeDetectionStrategy.OnPush,
11+
})
12+
export class CdkVirtualScrollDataSourceExample {
13+
ds = new MyDataSource();
14+
}
15+
16+
export class MyDataSource extends DataSource<string | undefined> {
17+
private length = 100000;
18+
private pageSize = 100;
19+
private cachedData = Array.from<string>({length: this.length});
20+
private fetchedPages = new Set<number>();
21+
private dataStream = new BehaviorSubject<(string | undefined)[]>(this.cachedData);
22+
private subscription = new Subscription();
23+
24+
connect(collectionViewer: CollectionViewer): Observable<(string | undefined)[]> {
25+
this.subscription.add(collectionViewer.viewChange.subscribe(range => {
26+
const startPage = this.getPageForIndex(range.start);
27+
const endPage = this.getPageForIndex(range.end - 1);
28+
for (let i = startPage; i <= endPage; i++) {
29+
this.fetchPage(i);
30+
}
31+
}));
32+
return this.dataStream;
33+
}
34+
35+
disconnect(): void {
36+
this.subscription.unsubscribe();
37+
}
38+
39+
private getPageForIndex(index: number): number {
40+
return Math.floor(index / this.pageSize);
41+
}
42+
43+
private fetchPage(page: number) {
44+
if (this.fetchedPages.has(page)) {
45+
return;
46+
}
47+
this.fetchedPages.add(page);
48+
49+
// Use `setTimeout` to simulate fetching data from server.
50+
setTimeout(() => {
51+
this.cachedData.splice(page * this.pageSize, this.pageSize,
52+
...Array.from({length: this.pageSize})
53+
.map((_, i) => `Item #${page * this.pageSize + i}`));
54+
this.dataStream.next(this.cachedData);
55+
}, Math.random() * 1000 + 200);
56+
}
57+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.example-viewport {
2+
height: 200px;
3+
width: 200px;
4+
border: 1px solid black;
5+
}
6+
7+
.example-dt {
8+
height: 30px;
9+
font-weight: bold;
10+
}
11+
12+
.example-dd {
13+
height: 30px;
14+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<cdk-virtual-scroll-viewport class="example-viewport" itemSize="60">
2+
<dl class="example-dl">
3+
<ng-container *cdkVirtualFor="let state of states">
4+
<dt class="example-dt">{{state.name}}</dt>
5+
<dd class="example-dd">{{state.capital}}</dd>
6+
</ng-container>
7+
</dl>
8+
</cdk-virtual-scroll-viewport>
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import {ChangeDetectionStrategy, Component} from '@angular/core';
2+
3+
/** @title Virtual scrolling `<dl>` */
4+
@Component({
5+
selector: 'cdk-virtual-scroll-dl-example',
6+
styleUrls: ['cdk-virtual-scroll-dl-example.css'],
7+
templateUrl: 'cdk-virtual-scroll-dl-example.html',
8+
changeDetection: ChangeDetectionStrategy.OnPush,
9+
})
10+
export class CdkVirtualScrollDlExample {
11+
states = [
12+
{name: 'Alabama', capital: 'Montgomery'},
13+
{name: 'Alaska', capital: 'Juneau'},
14+
{name: 'Arizona', capital: 'Phoenix'},
15+
{name: 'Arkansas', capital: 'Little Rock'},
16+
{name: 'California', capital: 'Sacramento'},
17+
{name: 'Colorado', capital: 'Denver'},
18+
{name: 'Connecticut', capital: 'Hartford'},
19+
{name: 'Delaware', capital: 'Dover'},
20+
{name: 'Florida', capital: 'Tallahassee'},
21+
{name: 'Georgia', capital: 'Atlanta'},
22+
{name: 'Hawaii', capital: 'Honolulu'},
23+
{name: 'Idaho', capital: 'Boise'},
24+
{name: 'Illinois', capital: 'Springfield'},
25+
{name: 'Indiana', capital: 'Indianapolis'},
26+
{name: 'Iowa', capital: 'Des Moines'},
27+
{name: 'Kansas', capital: 'Topeka'},
28+
{name: 'Kentucky', capital: 'Frankfort'},
29+
{name: 'Louisiana', capital: 'Baton Rouge'},
30+
{name: 'Maine', capital: 'Augusta'},
31+
{name: 'Maryland', capital: 'Annapolis'},
32+
{name: 'Massachusetts', capital: 'Boston'},
33+
{name: 'Michigan', capital: 'Lansing'},
34+
{name: 'Minnesota', capital: 'St. Paul'},
35+
{name: 'Mississippi', capital: 'Jackson'},
36+
{name: 'Missouri', capital: 'Jefferson City'},
37+
{name: 'Montana', capital: 'Helena'},
38+
{name: 'Nebraska', capital: 'Lincoln'},
39+
{name: 'Nevada', capital: 'Carson City'},
40+
{name: 'New Hampshire', capital: 'Concord'},
41+
{name: 'New Jersey', capital: 'Trenton'},
42+
{name: 'New Mexico', capital: 'Santa Fe'},
43+
{name: 'New York', capital: 'Albany'},
44+
{name: 'North Carolina', capital: 'Raleigh'},
45+
{name: 'North Dakota', capital: 'Bismarck'},
46+
{name: 'Ohio', capital: 'Columbus'},
47+
{name: 'Oklahoma', capital: 'Oklahoma City'},
48+
{name: 'Oregon', capital: 'Salem'},
49+
{name: 'Pennsylvania', capital: 'Harrisburg'},
50+
{name: 'Rhode Island', capital: 'Providence'},
51+
{name: 'South Carolina', capital: 'Columbia'},
52+
{name: 'South Dakota', capital: 'Pierre'},
53+
{name: 'Tennessee', capital: 'Nashville'},
54+
{name: 'Texas', capital: 'Austin'},
55+
{name: 'Utah', capital: 'Salt Lake City'},
56+
{name: 'Vermont', capital: 'Montpelier'},
57+
{name: 'Virginia', capital: 'Richmond'},
58+
{name: 'Washington', capital: 'Olympia'},
59+
{name: 'West Virginia', capital: 'Charleston'},
60+
{name: 'Wisconsin', capital: 'Madison'},
61+
{name: 'Wyoming', capital: 'Cheyenne'},
62+
];
63+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.example-viewport {
2+
height: 200px;
3+
width: 200px;
4+
border: 1px solid black;
5+
}
6+
7+
.example-item {
8+
height: 50px;
9+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<cdk-virtual-scroll-viewport itemSize="50" minBufferPx="200" maxBufferPx="400"
2+
class="example-viewport">
3+
<div *cdkVirtualFor="let item of items" class="example-item">{{item}}</div>
4+
</cdk-virtual-scroll-viewport>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import {ChangeDetectionStrategy, Component} from '@angular/core';
2+
3+
/** @title Fixed size virtual scroll with custom buffer parameters */
4+
@Component({
5+
selector: 'cdk-virtual-scroll-fixed-buffer-example',
6+
styleUrls: ['cdk-virtual-scroll-fixed-buffer-example.css'],
7+
templateUrl: 'cdk-virtual-scroll-fixed-buffer-example.html',
8+
changeDetection: ChangeDetectionStrategy.OnPush,
9+
})
10+
export class CdkVirtualScrollFixedBufferExample {
11+
items = Array.from({length: 100000}).map((_, i) => `Item #${i}`);
12+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
.cdk-virtual-scroll-data-source-example .example-viewport {
2+
height: 200px;
3+
width: 200px;
4+
border: 1px solid black;
5+
}
6+
7+
.cdk-virtual-scroll-data-source-example .example-viewport .cdk-virtual-scroll-content-wrapper {
8+
display: flex;
9+
flex-direction: row;
10+
}
11+
12+
.cdk-virtual-scroll-data-source-example .example-item {
13+
width: 50px;
14+
height: 100%;
15+
writing-mode: vertical-lr;
16+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<div class="cdk-virtual-scroll-data-source-example">
2+
<cdk-virtual-scroll-viewport orientation="horizontal" itemSize="50" class="example-viewport">
3+
<div *cdkVirtualFor="let item of items" class="example-item">{{item}}</div>
4+
</cdk-virtual-scroll-viewport>
5+
</div>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import {ChangeDetectionStrategy, Component, ViewEncapsulation} from '@angular/core';
2+
3+
/** @title Horizontal virtual scroll */
4+
@Component({
5+
selector: 'cdk-virtual-scroll-horizontal-example',
6+
styleUrls: ['cdk-virtual-scroll-horizontal-example.css'],
7+
templateUrl: 'cdk-virtual-scroll-horizontal-example.html',
8+
encapsulation: ViewEncapsulation.None,
9+
changeDetection: ChangeDetectionStrategy.OnPush,
10+
})
11+
export class CdkVirtualScrollHorizontalExample {
12+
items = Array.from({length: 100000}).map((_, i) => `Item #${i}`);
13+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.example-viewport {
2+
height: 200px;
3+
width: 200px;
4+
border: 1px solid black;
5+
}
6+
7+
.example-item {
8+
height: 50px;
9+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<cdk-virtual-scroll-viewport itemSize="50" class="example-viewport">
2+
<div *cdkVirtualFor="let item of items" class="example-item">{{item}}</div>
3+
</cdk-virtual-scroll-viewport>

0 commit comments

Comments
 (0)