(viewport: CdkVirtualScrollViewport)
| 1492 | } |
| 1493 | |
| 1494 | private _setupVirtualScrolling(viewport: CdkVirtualScrollViewport) { |
| 1495 | const virtualScrollScheduler = |
| 1496 | typeof requestAnimationFrame !== 'undefined' ? animationFrameScheduler : asapScheduler; |
| 1497 | |
| 1498 | // Render nothing since the virtual scroll viewport will take over. |
| 1499 | this.viewChange.next({start: 0, end: 0}); |
| 1500 | |
| 1501 | // Forward the rendered range computed by the virtual scroll viewport to the table. |
| 1502 | viewport.renderedRangeStream |
| 1503 | // We need the scheduler here, because the virtual scrolling module uses an identical |
| 1504 | // one for scroll listeners. Without it the two go out of sync and the list starts |
| 1505 | // jumping back to the beginning whenever it needs to re-render. |
| 1506 | .pipe(auditTime(0, virtualScrollScheduler), takeUntil(this._onDestroy)) |
| 1507 | .subscribe(this.viewChange); |
| 1508 | |
| 1509 | viewport.attach({ |
| 1510 | dataStream: this._dataStream, |
| 1511 | measureRangeSize: (range, orientation) => this._measureRangeSize(range, orientation), |
| 1512 | }); |
| 1513 | |
| 1514 | // The `StyickyStyler` sticks elements by applying a `top` or `bottom` position offset to |
| 1515 | // them. However, the virtual scroll viewport applies a `translateY` offset to a container |
| 1516 | // div that encapsulates the table. The translation causes the rows to also be offset by the |
| 1517 | // distance from the top of the scroll viewport in addition to their `top` offset. This logic |
| 1518 | // negates the translation to move the rows to their correct positions. |
| 1519 | combineLatest([viewport.renderedContentOffset, this._headerRowStickyUpdates]) |
| 1520 | .pipe(takeUntil(this._onDestroy)) |
| 1521 | .subscribe(([offsetFromTop, update]) => { |
| 1522 | if (!update.sizes || !update.offsets || !update.elements) { |
| 1523 | return; |
| 1524 | } |
| 1525 | |
| 1526 | for (let i = 0; i < update.elements.length; i++) { |
| 1527 | const cells = update.elements[i]; |
| 1528 | |
| 1529 | if (cells) { |
| 1530 | const current = update.offsets[i]!; |
| 1531 | const offset = |
| 1532 | offsetFromTop !== 0 ? Math.max(offsetFromTop - current, current) : -current; |
| 1533 | |
| 1534 | for (const cell of cells) { |
| 1535 | cell.style.top = `${-offset}px`; |
| 1536 | } |
| 1537 | } |
| 1538 | } |
| 1539 | }); |
| 1540 | |
| 1541 | combineLatest([viewport.renderedContentOffset, this._footerRowStickyUpdates]) |
| 1542 | .pipe(takeUntil(this._onDestroy)) |
| 1543 | .subscribe(([offsetFromTop, update]) => { |
| 1544 | if (!update.sizes || !update.offsets || !update.elements) { |
| 1545 | return; |
| 1546 | } |
| 1547 | |
| 1548 | for (let i = 0; i < update.elements.length; i++) { |
| 1549 | const cells = update.elements[i]; |
| 1550 | |
| 1551 | if (cells) { |
no test coverage detected