@@ -43,8 +43,10 @@ import {VIRTUAL_SCROLL_STRATEGY, VirtualScrollStrategy} from './virtual-scroll-s
43
43
preserveWhitespaces : false ,
44
44
} )
45
45
export class CdkVirtualScrollViewport implements OnInit , DoCheck , OnDestroy {
46
- private _disconnectSubject = new Subject < void > ( ) ;
46
+ /** Emits when the viewport is detached from a CdkVirtualForOf. */
47
+ private _detachedSubject = new Subject < void > ( ) ;
47
48
49
+ /** Emits when the rendered range changes. */
48
50
private _renderedRangeSubject = new Subject < Range > ( ) ;
49
51
50
52
/** The direction the viewport scrolls. */
@@ -53,73 +55,99 @@ export class CdkVirtualScrollViewport implements OnInit, DoCheck, OnDestroy {
53
55
/** The element that wraps the rendered content. */
54
56
@ViewChild ( 'contentWrapper' ) _contentWrapper : ElementRef ;
55
57
56
- /** The total size of all content, including content that is not currently rendered. */
57
- get totalContentSize ( ) { return this . _totalContentSize ; }
58
- set totalContentSize ( size : number ) {
58
+ /** A stream that emits whenever the rendered range changes. */
59
+ renderedRangeStream : Observable < Range > = this . _renderedRangeSubject . asObservable ( ) ;
60
+
61
+ /**
62
+ * The total size of all content (in pixels), including content that is not currently rendered.
63
+ */
64
+ _totalContentSize = 0 ;
65
+
66
+ /** The transform used to offset the rendered content wrapper element. */
67
+ _renderedContentTransform : string ;
68
+
69
+ /** The currently rendered range of indices. */
70
+ private _renderedRange : Range = { start : 0 , end : 0 } ;
71
+
72
+ /** The length of the data bound to this viewport (in number of items). */
73
+ private _dataLength = 0 ;
74
+
75
+ /** The size of the viewport (in pixels). */
76
+ private _viewportSize = 0 ;
77
+
78
+ /** Whether this viewport is attached to a CdkVirtualForOf. */
79
+ private _isAttached = false ;
80
+
81
+ /**
82
+ * The scroll handling status.
83
+ * needed - The scroll state needs to be updated, but a check hasn't yet been scheduled.
84
+ * pending - The scroll state needs to be updated, and an update has already been scheduled.
85
+ * done - The scroll state does not need to be updated.
86
+ */
87
+ private _scrollHandledStatus : 'needed' | 'pending' | 'done' = 'done' ;
88
+
89
+ constructor ( public elementRef : ElementRef , private _changeDetectorRef : ChangeDetectorRef ,
90
+ private _ngZone : NgZone ,
91
+ @Inject ( VIRTUAL_SCROLL_STRATEGY ) private _scrollStrategy : VirtualScrollStrategy ) { }
92
+
93
+ /** Gets the length of the data bound to this viewport (in number of items). */
94
+ getDataLength ( ) : number {
95
+ return this . _dataLength ;
96
+ }
97
+
98
+ /** Gets the size of the viewport (in pixels). */
99
+ getViewportSize ( ) : number {
100
+ return this . _viewportSize ;
101
+ }
102
+
103
+ /**
104
+ * Sets the total size of all content (in pixels), including content that is not currently
105
+ * rendered.
106
+ */
107
+ setTotalContentSize ( size : number ) {
59
108
if ( this . _totalContentSize != size ) {
109
+ // Re-enter the Angular zone so we can mark for change detection.
60
110
this . _ngZone . run ( ( ) => {
61
111
this . _totalContentSize = size ;
62
112
this . _changeDetectorRef . markForCheck ( ) ;
63
113
} ) ;
64
114
}
65
115
}
66
- private _totalContentSize = 0 ;
67
116
68
- /** The currently rendered range of indices. */
69
- get renderedRange ( ) { return this . _renderedRange ; }
70
- set renderedRange ( range : Range ) {
117
+ /** Sets the currently rendered range of indices. */
118
+ setRenderedRange ( range : Range ) {
71
119
if ( ! this . _rangesEqual ( this . _renderedRange , range ) ) {
120
+ // Re-enter the Angular zone so we can mark for change detection.
72
121
this . _ngZone . run ( ( ) => {
73
122
this . _renderedRangeSubject . next ( this . _renderedRange = range ) ;
74
123
this . _changeDetectorRef . markForCheck ( ) ;
75
124
} ) ;
76
125
}
77
126
}
78
- private _renderedRange : Range = { start : 0 , end : 0 } ;
79
127
80
- /** The offset of the rendered portion of the data from the start. */
81
- get renderedContentOffset ( ) : number { return this . _renderedContentOffset ; }
82
- set renderedContentOffset ( offset : number ) {
83
- if ( this . _renderedContentOffset != offset ) {
128
+ /** Sets the offset of the rendered portion of the data from the start (in pixels). */
129
+ setRenderedContentOffset ( offset : number ) {
130
+ const transform =
131
+ this . orientation === 'horizontal' ? `translateX(${ offset } px)` : `translateY(${ offset } px)` ;
132
+ if ( this . _renderedContentTransform != transform ) {
133
+ // Re-enter the Angular zone so we can mark for change detection.
84
134
this . _ngZone . run ( ( ) => {
85
- this . _renderedContentOffset = offset ;
86
- this . _renderedContentTransform = this . orientation === 'horizontal' ?
87
- `translateX(${ offset } px)` : `translateY(${ offset } px)` ;
135
+ this . _renderedContentTransform = transform ;
88
136
this . _changeDetectorRef . markForCheck ( ) ;
89
137
} ) ;
90
138
}
91
139
}
92
- private _renderedContentOffset = 0 ;
93
-
94
- /** The length of the data connected to this viewport. */
95
- get dataLength ( ) { return this . _dataLength ; }
96
- private _dataLength = 0 ;
97
-
98
- /** The size of the viewport. */
99
- get viewportSize ( ) { return this . _viewportSize ; }
100
- private _viewportSize = 0 ;
101
-
102
- /** A stream that emits whenever the rendered range changes. */
103
- renderedRangeStream : Observable < Range > = this . _renderedRangeSubject . asObservable ( ) ;
104
-
105
- _renderedContentTransform : string ;
106
-
107
- private _connected = false ;
108
-
109
- private _scrollHandledStatus : 'needed' | 'pending' | 'done' = 'done' ;
110
-
111
- constructor ( public elementRef : ElementRef , private _changeDetectorRef : ChangeDetectorRef ,
112
- private _ngZone : NgZone ,
113
- @Inject ( VIRTUAL_SCROLL_STRATEGY ) private _scrollStrategy : VirtualScrollStrategy ) { }
114
140
115
- /** Connect a `CdkVirtualForOf` to this viewport. */
116
- connect ( forOf : CdkVirtualForOf < any > ) {
117
- if ( this . _connected ) {
118
- throw Error ( 'CdkVirtualScrollViewport is already connected .' ) ;
141
+ /** Attaches a `CdkVirtualForOf` to this viewport. */
142
+ attach ( forOf : CdkVirtualForOf < any > ) {
143
+ if ( this . _isAttached ) {
144
+ throw Error ( 'CdkVirtualScrollViewport is already attached .' ) ;
119
145
}
120
146
121
- this . _connected = true ;
122
- forOf . dataStream . pipe ( takeUntil ( this . _disconnectSubject ) ) . subscribe ( data => {
147
+ this . _isAttached = true ;
148
+ // Subscribe to the data stream of the CdkVirtualForOf to keep track of when the data length
149
+ // changes.
150
+ forOf . dataStream . pipe ( takeUntil ( this . _detachedSubject ) ) . subscribe ( data => {
123
151
const len = data . length ;
124
152
if ( len != this . _dataLength ) {
125
153
this . _dataLength = len ;
@@ -128,13 +156,13 @@ export class CdkVirtualScrollViewport implements OnInit, DoCheck, OnDestroy {
128
156
} ) ;
129
157
}
130
158
131
- /** Disconnect the current `CdkVirtualForOf`. */
132
- disconnect ( ) {
133
- this . _connected = false ;
134
- this . _disconnectSubject . next ( ) ;
159
+ /** Detaches the current `CdkVirtualForOf`. */
160
+ detach ( ) {
161
+ this . _isAttached = false ;
162
+ this . _detachedSubject . next ( ) ;
135
163
}
136
164
137
- /** Gets the current scroll offset of the viewport. */
165
+ /** Gets the current scroll offset of the viewport (in pixels) . */
138
166
measureScrollOffset ( ) {
139
167
return this . orientation === 'horizontal' ?
140
168
this . elementRef . nativeElement . scrollLeft : this . elementRef . nativeElement . scrollTop ;
@@ -164,23 +192,26 @@ export class CdkVirtualScrollViewport implements OnInit, DoCheck, OnDestroy {
164
192
}
165
193
166
194
ngOnDestroy ( ) {
167
- this . disconnect ( ) ;
195
+ this . detach ( ) ;
168
196
this . _scrollStrategy . detach ( ) ;
169
197
170
198
// Complete all subjects
171
- this . _disconnectSubject . complete ( ) ;
199
+ this . _detachedSubject . complete ( ) ;
172
200
this . _renderedRangeSubject . complete ( ) ;
173
201
}
174
202
203
+ /** Marks that a scroll event happened and that the scroll state should be checked. */
175
204
private _markScrolled ( ) {
176
205
if ( this . _scrollHandledStatus === 'done' ) {
206
+ // Re-enter the Angular zone so we can mark for change detection.
177
207
this . _ngZone . run ( ( ) => {
178
208
this . _scrollHandledStatus = 'needed' ;
179
209
this . _changeDetectorRef . markForCheck ( ) ;
180
210
} ) ;
181
211
}
182
212
}
183
213
214
+ /** Checks if the given ranges are equal. */
184
215
private _rangesEqual ( r1 : Range , r2 : Range ) : boolean {
185
216
return r1 . start == r2 . start && r1 . end == r2 . end ;
186
217
}
0 commit comments