Skip to content

docs(virtual-scroll): add embedded examples #13327

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 8 additions & 45 deletions src/cdk/scrolling/scrolling.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,7 @@ rest.
same API as [`*ngFor`](https://angular.io/api/common/NgForOf). The simplest usage just specifies the
list of items:

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

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

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

```html
<cdk-virtual-scroll-viewport itemSize="50">
<div *cdkVirtualFor="let item of items;
let index = index;
let count = count">
{{item}} ({{index}} of {{count}})
</div>
</cdk-virtual-scroll-viewport>
```
<!-- example(cdk-virtual-scroll-context) -->

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

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

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

<!-- example(cdk-virtual-scroll-data-source) -->

#### Scrolling over fixed size items
When all items are the same fixed size, you can use the `FixedSizeVirtualScrollStrategy`. This can
be easily added to your viewport using the `itemSize` directive. The advantage of this constraint is
that it allows for better performance, since items do not need to be measured as they are rendered.

```html
<cdk-virtual-scroll-viewport itemSize="50">
...
</cdk-virtual-scroll-viewport>
```

The fixed size strategy also supports setting a couple of buffer parameters that determine how much
extra content is rendered beyond what is visible in the viewport. The first of these parameters is
`minBufferPx`. The `minBufferPx` is the minimum amount of content buffer (in pixels) that the
Expand All @@ -108,11 +88,7 @@ remaining. Since this is below `minBufferPx` the viewport must render more buffe
least enough buffer to get back to `maxBufferPx`. In this case, it renders 4 items (an additional
`200px`) to bring the total buffer size to `290px`, back above `maxBufferPx`.

```html
<cdk-virtual-scroll-viewport itemSize="50" minBufferPx="100" maxBufferPx="250">
...
</cdk-virtual-scroll-viewport>
```
<!-- example(cdk-virtual-scroll-fixed-buffer) -->

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

```html
<cdk-virtual-scroll-viewport itemSize="50" orientation="horizontal">
...
</cdk-virtual-scroll-viewport>
```
<!-- example(cdk-virtual-scroll-horizontal) -->

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

```html
<cdk-virtual-scroll-viewport itemSize="50">
<table>
<tr *cdkVirtualFor="let row of rows">
<td>{{row.first}}</td>
<td>{{row.second}}</td>
</tr>
</table>
</cdk-virtual-scroll-viewport>
```
<!-- example(cdk-virtual-scroll-dl) -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.example-viewport {
height: 200px;
width: 200px;
border: 1px solid black;
}

.example-item-detail {
height: 18px;
}

.example-alternate {
background: rgba(127, 127, 127, 0.3);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<cdk-virtual-scroll-viewport [itemSize]="18 * 7" class="example-viewport">
<div *cdkVirtualFor="let item of items;
let index = index;
let count = count;
let first = first;
let last = last;
let even = even;
let odd = odd;" [class.example-alternate]="odd">
<div class="example-item-detail">Item: {{item}}</div>
<div class="example-item-detail">Index: {{index}}</div>
<div class="example-item-detail">Count: {{count}}</div>
<div class="example-item-detail">First: {{first ? 'Yes' : 'No'}}</div>
<div class="example-item-detail">Last: {{last ? 'Yes' : 'No'}}</div>
<div class="example-item-detail">Event: {{even ? 'Yes' : 'No'}}</div>
<div class="example-item-detail">Odd: {{odd ? 'Yes' : 'No'}}</div>
</div>
</cdk-virtual-scroll-viewport>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {ChangeDetectionStrategy, Component} from '@angular/core';

/** @title Virtual scroll context variables */
@Component({
selector: 'cdk-virtual-scroll-context-example',
styleUrls: ['cdk-virtual-scroll-context-example.css'],
templateUrl: 'cdk-virtual-scroll-context-example.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CdkVirtualScrollContextExample {
items = Array.from({length: 100000}).map((_, i) => `Item #${i}`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Can be reduced to new Array(100000).fill(0).map((_, i) => Item #${i}) which is slightly shorter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I originally had that but switched it to this. This feels more readable to me, so I think its better for the purposes of an example.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.example-viewport {
height: 200px;
width: 200px;
border: 1px solid black;
}

.example-item {
height: 50px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<cdk-virtual-scroll-viewport itemSize="50" class="example-viewport">
<div *cdkVirtualFor="let item of ds" class="example-item">{{item || 'Loading...'}}</div>
</cdk-virtual-scroll-viewport>
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import {CollectionViewer, DataSource} from '@angular/cdk/collections';
import {ChangeDetectionStrategy, Component} from '@angular/core';
import {BehaviorSubject, Observable, Subscription} from 'rxjs';

/** @title Virtual scroll with a custom data source */
@Component({
selector: 'cdk-virtual-scroll-data-source-example',
styleUrls: ['cdk-virtual-scroll-data-source-example.css'],
templateUrl: 'cdk-virtual-scroll-data-source-example.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CdkVirtualScrollDataSourceExample {
ds = new MyDataSource();
}

export class MyDataSource extends DataSource<string | undefined> {
private length = 100000;
private pageSize = 100;
private cachedData = Array.from<string>({length: this.length});
private fetchedPages = new Set<number>();
private dataStream = new BehaviorSubject<(string | undefined)[]>(this.cachedData);
private subscription = new Subscription();

connect(collectionViewer: CollectionViewer): Observable<(string | undefined)[]> {
this.subscription.add(collectionViewer.viewChange.subscribe(range => {
const startPage = this.getPageForIndex(range.start);
const endPage = this.getPageForIndex(range.end - 1);
for (let i = startPage; i <= endPage; i++) {
this.fetchPage(i);
}
}));
return this.dataStream;
}

disconnect(): void {
this.subscription.unsubscribe();
}

private getPageForIndex(index: number): number {
return Math.floor(index / this.pageSize);
}

private fetchPage(page: number) {
if (this.fetchedPages.has(page)) {
return;
}
this.fetchedPages.add(page);

// Use `setTimeout` to simulate fetching data from server.
setTimeout(() => {
this.cachedData.splice(page * this.pageSize, this.pageSize,
...Array.from({length: this.pageSize})
.map((_, i) => `Item #${page * this.pageSize + i}`));
this.dataStream.next(this.cachedData);
}, Math.random() * 1000 + 200);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.example-viewport {
height: 200px;
width: 200px;
border: 1px solid black;
}

.example-dt {
height: 30px;
font-weight: bold;
}

.example-dd {
height: 30px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<cdk-virtual-scroll-viewport class="example-viewport" itemSize="60">
<dl class="example-dl">
<ng-container *cdkVirtualFor="let state of states">
<dt class="example-dt">{{state.name}}</dt>
<dd class="example-dd">{{state.capital}}</dd>
</ng-container>
</dl>
</cdk-virtual-scroll-viewport>
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import {ChangeDetectionStrategy, Component} from '@angular/core';

/** @title Virtual scrolling `<dl>` */
@Component({
selector: 'cdk-virtual-scroll-dl-example',
styleUrls: ['cdk-virtual-scroll-dl-example.css'],
templateUrl: 'cdk-virtual-scroll-dl-example.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CdkVirtualScrollDlExample {
states = [
{name: 'Alabama', capital: 'Montgomery'},
{name: 'Alaska', capital: 'Juneau'},
{name: 'Arizona', capital: 'Phoenix'},
{name: 'Arkansas', capital: 'Little Rock'},
{name: 'California', capital: 'Sacramento'},
{name: 'Colorado', capital: 'Denver'},
{name: 'Connecticut', capital: 'Hartford'},
{name: 'Delaware', capital: 'Dover'},
{name: 'Florida', capital: 'Tallahassee'},
{name: 'Georgia', capital: 'Atlanta'},
{name: 'Hawaii', capital: 'Honolulu'},
{name: 'Idaho', capital: 'Boise'},
{name: 'Illinois', capital: 'Springfield'},
{name: 'Indiana', capital: 'Indianapolis'},
{name: 'Iowa', capital: 'Des Moines'},
{name: 'Kansas', capital: 'Topeka'},
{name: 'Kentucky', capital: 'Frankfort'},
{name: 'Louisiana', capital: 'Baton Rouge'},
{name: 'Maine', capital: 'Augusta'},
{name: 'Maryland', capital: 'Annapolis'},
{name: 'Massachusetts', capital: 'Boston'},
{name: 'Michigan', capital: 'Lansing'},
{name: 'Minnesota', capital: 'St. Paul'},
{name: 'Mississippi', capital: 'Jackson'},
{name: 'Missouri', capital: 'Jefferson City'},
{name: 'Montana', capital: 'Helena'},
{name: 'Nebraska', capital: 'Lincoln'},
{name: 'Nevada', capital: 'Carson City'},
{name: 'New Hampshire', capital: 'Concord'},
{name: 'New Jersey', capital: 'Trenton'},
{name: 'New Mexico', capital: 'Santa Fe'},
{name: 'New York', capital: 'Albany'},
{name: 'North Carolina', capital: 'Raleigh'},
{name: 'North Dakota', capital: 'Bismarck'},
{name: 'Ohio', capital: 'Columbus'},
{name: 'Oklahoma', capital: 'Oklahoma City'},
{name: 'Oregon', capital: 'Salem'},
{name: 'Pennsylvania', capital: 'Harrisburg'},
{name: 'Rhode Island', capital: 'Providence'},
{name: 'South Carolina', capital: 'Columbia'},
{name: 'South Dakota', capital: 'Pierre'},
{name: 'Tennessee', capital: 'Nashville'},
{name: 'Texas', capital: 'Austin'},
{name: 'Utah', capital: 'Salt Lake City'},
{name: 'Vermont', capital: 'Montpelier'},
{name: 'Virginia', capital: 'Richmond'},
{name: 'Washington', capital: 'Olympia'},
{name: 'West Virginia', capital: 'Charleston'},
{name: 'Wisconsin', capital: 'Madison'},
{name: 'Wyoming', capital: 'Cheyenne'},
];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.example-viewport {
height: 200px;
width: 200px;
border: 1px solid black;
}

.example-item {
height: 50px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<cdk-virtual-scroll-viewport itemSize="50" minBufferPx="200" maxBufferPx="400"
class="example-viewport">
<div *cdkVirtualFor="let item of items" class="example-item">{{item}}</div>
</cdk-virtual-scroll-viewport>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {ChangeDetectionStrategy, Component} from '@angular/core';

/** @title Fixed size virtual scroll with custom buffer parameters */
@Component({
selector: 'cdk-virtual-scroll-fixed-buffer-example',
styleUrls: ['cdk-virtual-scroll-fixed-buffer-example.css'],
templateUrl: 'cdk-virtual-scroll-fixed-buffer-example.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CdkVirtualScrollFixedBufferExample {
items = Array.from({length: 100000}).map((_, i) => `Item #${i}`);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.cdk-virtual-scroll-data-source-example .example-viewport {
height: 200px;
width: 200px;
border: 1px solid black;
}

.cdk-virtual-scroll-data-source-example .example-viewport .cdk-virtual-scroll-content-wrapper {
display: flex;
flex-direction: row;
}

.cdk-virtual-scroll-data-source-example .example-item {
width: 50px;
height: 100%;
writing-mode: vertical-lr;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div class="cdk-virtual-scroll-data-source-example">
<cdk-virtual-scroll-viewport orientation="horizontal" itemSize="50" class="example-viewport">
<div *cdkVirtualFor="let item of items" class="example-item">{{item}}</div>
</cdk-virtual-scroll-viewport>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {ChangeDetectionStrategy, Component, ViewEncapsulation} from '@angular/core';

/** @title Horizontal virtual scroll */
@Component({
selector: 'cdk-virtual-scroll-horizontal-example',
styleUrls: ['cdk-virtual-scroll-horizontal-example.css'],
templateUrl: 'cdk-virtual-scroll-horizontal-example.html',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CdkVirtualScrollHorizontalExample {
items = Array.from({length: 100000}).map((_, i) => `Item #${i}`);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.example-viewport {
height: 200px;
width: 200px;
border: 1px solid black;
}

.example-item {
height: 50px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<cdk-virtual-scroll-viewport itemSize="50" class="example-viewport">
<div *cdkVirtualFor="let item of items" class="example-item">{{item}}</div>
</cdk-virtual-scroll-viewport>
Loading