@@ -86,6 +86,15 @@ export class CdkVirtualScrollViewport implements DoCheck, OnInit, OnDestroy {
86
86
/** the currently attached CdkVirtualForOf. */
87
87
private _forOf : CdkVirtualForOf < any > | null ;
88
88
89
+ /** The last rendered content offset that was set. */
90
+ private _renderedContentOffset = 0 ;
91
+
92
+ /**
93
+ * Whether the last rendered content offset was to the end of the content (and therefore needs to
94
+ * be rewritten as an offset to the start of the content).
95
+ */
96
+ private _renderedContentOffsetNeedsRewrite = false ;
97
+
89
98
constructor ( public elementRef : ElementRef , private _changeDetectorRef : ChangeDetectorRef ,
90
99
private _ngZone : NgZone , private _sanitizer : DomSanitizer ,
91
100
@Inject ( VIRTUAL_SCROLL_STRATEGY ) private _scrollStrategy : VirtualScrollStrategy ) { }
@@ -204,21 +213,43 @@ export class CdkVirtualScrollViewport implements DoCheck, OnInit, OnDestroy {
204
213
// viewport.setRenderedContentOffset(...);
205
214
//
206
215
// The call to `onContentRendered` will happen after all of the updates have been applied.
207
- Promise . resolve ( ) . then ( ( ) => this . _scrollStrategy . onContentRendered ( ) ) ;
216
+ Promise . resolve ( ) . then ( ( ) => {
217
+ // If the rendered content offset was specified as an offset to the end of the content,
218
+ // rewrite it as an offset to the start of the content.
219
+ if ( this . _renderedContentOffsetNeedsRewrite ) {
220
+ this . _renderedContentOffset -= this . measureRenderedContentSize ( ) ;
221
+ this . _renderedContentOffsetNeedsRewrite = false ;
222
+ this . setRenderedContentOffset ( this . _renderedContentOffset ) ;
223
+ }
224
+
225
+ this . _scrollStrategy . onContentRendered ( ) ;
226
+ } ) ;
208
227
} ) ) ;
209
228
} ) ;
210
229
}
211
230
}
212
231
213
- /** Sets the offset of the rendered portion of the data from the start (in pixels). */
232
+ /**
233
+ * Gets the offset from the start of the viewport to the start of the rendered data (in pixels).
234
+ */
235
+ getOffsetToRenderedContentStart ( ) : number | null {
236
+ return this . _renderedContentOffsetNeedsRewrite ? null : this . _renderedContentOffset ;
237
+ }
238
+
239
+ /**
240
+ * Sets the offset from the start of the viewport to either the start or end of the rendered data
241
+ * (in pixels).
242
+ */
214
243
setRenderedContentOffset ( offset : number , to : 'to-start' | 'to-end' = 'to-start' ) {
215
244
const axis = this . orientation === 'horizontal' ? 'X' : 'Y' ;
216
245
let transform = `translate${ axis } (${ Number ( offset ) } px)` ;
246
+ this . _renderedContentOffset = offset ;
217
247
if ( to === 'to-end' ) {
218
248
// TODO(mmalerba): The viewport should rewrite this as a `to-start` offset on the next render
219
249
// cycle. Otherwise elements will appear to expand in the wrong direction (e.g.
220
250
// `mat-expansion-panel` would expand upward).
221
251
transform += ` translate${ axis } (-100%)` ;
252
+ this . _renderedContentOffsetNeedsRewrite = true ;
222
253
}
223
254
if ( this . _renderedContentTransform != transform ) {
224
255
// Re-enter the Angular zone so we can mark for change detection.
@@ -253,21 +284,6 @@ export class CdkVirtualScrollViewport implements DoCheck, OnInit, OnDestroy {
253
284
return this . orientation === 'horizontal' ? contentEl . offsetWidth : contentEl . offsetHeight ;
254
285
}
255
286
256
- // TODO(mmalerba): Try to do this in a way that's less bad for performance. (The bad part here is
257
- // that we have to measure the viewport which is not absolutely positioned.)
258
- /** Measure the offset from the start of the viewport to the start of the rendered content. */
259
- measureRenderedContentOffset ( ) : number {
260
- const viewportEl = this . elementRef . nativeElement ;
261
- const contentEl = this . _contentWrapper . nativeElement ;
262
- if ( this . orientation === 'horizontal' ) {
263
- return contentEl . getBoundingClientRect ( ) . left + viewportEl . scrollLeft -
264
- viewportEl . getBoundingClientRect ( ) . left - viewportEl . clientLeft ;
265
- } else {
266
- return contentEl . getBoundingClientRect ( ) . top + viewportEl . scrollTop -
267
- viewportEl . getBoundingClientRect ( ) . top - viewportEl . clientTop ;
268
- }
269
- }
270
-
271
287
/**
272
288
* Measure the total combined size of the given range. Throws if the range includes items that are
273
289
* not rendered.
0 commit comments