Skip to content

Commit 8cfaeea

Browse files
mmalerbaandrewseguin
authored andcommitted
fix(virtual-scroll): fix several small bugs (#13597)
* fix(virtual-scroll): fix several small bugs fixes include: * ensure content wrapper is at least as wide as the viewport * run change detection when data source emits but the data length remains the same * improve error message when no virtual scroll strategy is provided * add docs on using a custom virtual scroll strategy * address comments * address feedback
1 parent 160b688 commit 8cfaeea

File tree

7 files changed

+77
-2
lines changed

7 files changed

+77
-2
lines changed

src/cdk/scrolling/scrolling.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ rest.
2525
#### Creating items in the viewport
2626
`*cdkVirtualFor` replaces `*ngFor` inside of a `<cdk-virtual-scroll-viewport>`, supporting the exact
2727
same API as [`*ngFor`](https://angular.io/api/common/NgForOf). The simplest usage just specifies the
28-
list of items:
28+
list of items (note that the `itemSize` property on the viewport must be set):
2929

3030
<!-- example(cdk-virtual-scroll-overview) -->
3131

@@ -111,3 +111,13 @@ that the parent does not introduce additional space (e.g. via `margin` or `paddi
111111
interfere with the scrolling.
112112

113113
<!-- example(cdk-virtual-scroll-dl) -->
114+
115+
### Scrolling strategies
116+
In order to determine how large the overall content is and what portion of it actually needs to be
117+
rendered at any given time the viewport relies on a `VirtualScrollStrategy` being provided. The
118+
simplest way to provide it is to use the `itemSize` directive on the viewport
119+
(e.g. `<cdk-virtual-scroll-viewport itemSize="50">`). However it is also possible to provide a
120+
custom strategy by creating a class that implements the `VirtualScrollStrategy` interface and
121+
providing it as the `VIRTUAL_SCROLL_STRATEGY` on the component containing your viewport.
122+
123+
<!-- example(cdk-virtual-scroll-custom-strategy) -->

src/cdk/scrolling/virtual-scroll-viewport.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,12 @@ cdk-virtual-scroll-viewport {
5656
}
5757

5858
.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper {
59+
min-height: 100%;
5960
@include _cdk-virtual-scroll-clear-container-space(horizontal);
6061
}
6162

6263
.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper {
64+
min-width: 100%;
6365
@include _cdk-virtual-scroll-clear-container-space(vertical);
6466
}
6567

src/cdk/scrolling/virtual-scroll-viewport.spec.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,20 @@ describe('CdkVirtualScrollViewport', () => {
717717
expect(viewport.elementRef.nativeElement.scrollWidth).toBe(10000);
718718
}));
719719
});
720+
721+
describe('with no VirtualScrollStrategy', () => {
722+
beforeEach(() => {
723+
TestBed.configureTestingModule({
724+
imports: [ScrollingModule],
725+
declarations: [VirtualScrollWithNoStrategy],
726+
}).compileComponents();
727+
});
728+
729+
it('should fail on construction', fakeAsync(() => {
730+
expect(() => TestBed.createComponent(VirtualScrollWithNoStrategy)).toThrowError(
731+
'Error: cdk-virtual-scroll-viewport requires the "itemSize" property to be set.');
732+
}));
733+
});
720734
});
721735

722736

@@ -848,3 +862,14 @@ class FixedSizeVirtualScrollWithRtlDirection {
848862
return this.orientation == 'horizontal' ? this.viewportCrossSize : this.viewportSize;
849863
}
850864
}
865+
866+
@Component({
867+
template: `
868+
<cdk-virtual-scroll-viewport>
869+
<div *cdkVirtualFor="let item of items">{{item}}</div>
870+
</cdk-virtual-scroll-viewport>
871+
`
872+
})
873+
class VirtualScrollWithNoStrategy {
874+
items = [];
875+
}

src/cdk/scrolling/virtual-scroll-viewport.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,15 @@ export class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, O
124124
constructor(public elementRef: ElementRef<HTMLElement>,
125125
private _changeDetectorRef: ChangeDetectorRef,
126126
ngZone: NgZone,
127-
@Inject(VIRTUAL_SCROLL_STRATEGY) private _scrollStrategy: VirtualScrollStrategy,
127+
@Optional() @Inject(VIRTUAL_SCROLL_STRATEGY)
128+
private _scrollStrategy: VirtualScrollStrategy,
128129
@Optional() dir: Directionality,
129130
scrollDispatcher: ScrollDispatcher) {
130131
super(elementRef, scrollDispatcher, ngZone, dir);
132+
133+
if (!_scrollStrategy) {
134+
throw Error('Error: cdk-virtual-scroll-viewport requires the "itemSize" property to be set.');
135+
}
131136
}
132137

133138
ngOnInit() {
@@ -183,6 +188,7 @@ export class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, O
183188
this._dataLength = newLength;
184189
this._scrollStrategy.onDataLengthChanged();
185190
}
191+
this._doChangeDetection();
186192
});
187193
});
188194
}
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+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<cdk-virtual-scroll-viewport class="example-viewport">
2+
<div *cdkVirtualFor="let item of items" class="example-item">{{item}}</div>
3+
</cdk-virtual-scroll-viewport>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import {FixedSizeVirtualScrollStrategy, VIRTUAL_SCROLL_STRATEGY} from '@angular/cdk/scrolling';
2+
import {ChangeDetectionStrategy, Component} from '@angular/core';
3+
4+
export class CustomVirtualScrollStrategy extends FixedSizeVirtualScrollStrategy {
5+
constructor() {
6+
super(50, 250, 500);
7+
}
8+
}
9+
10+
/** @title Virtual scroll with a custom strategy */
11+
@Component({
12+
selector: 'cdk-virtual-scroll-custom-strategy-example',
13+
styleUrls: ['cdk-virtual-scroll-custom-strategy-example.css'],
14+
templateUrl: 'cdk-virtual-scroll-custom-strategy-example.html',
15+
changeDetection: ChangeDetectionStrategy.OnPush,
16+
providers: [{provide: VIRTUAL_SCROLL_STRATEGY, useClass: CustomVirtualScrollStrategy}]
17+
})
18+
export class CdkVirtualScrollCustomStrategyExample {
19+
items = Array.from({length: 100000}).map((_, i) => `Item #${i}`);
20+
}

0 commit comments

Comments
 (0)